I have a program which consists of multiple threads.
These threads have to synchronize at some point, continue together, do their work of different lengths and then synchronize again.
Here's the example of what I mean:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define NUM_THREADS 10
void* thread(void* idp);
int threads_running = 0;
pthread_mutex_t* mutex;
pthread_cond_t* cond;
int main(int args, char **argv)
{
pthread_mutex_t mutex_var;
pthread_cond_t cond_var;
mutex = &mutex_var;
cond = &cond_var;
pthread_mutex_init(mutex, NULL);
pthread_cond_init(cond, NULL);
pthread_t threads[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; i++)
{
printf("Creating Thread %d....\n", i);
int* id = malloc(sizeof(int));
*id = i;
if(0 != pthread_create(&threads[i], NULL, thread, (void *) id))
{
perror("Error while creating the threads");
exit(1);
}
}
for (int i = 0; i < NUM_THREADS; i++)
{
pthread_join(threads[i], NULL);
}
return 0;
}
void* thread(void* idp)
{
int* id = (int*) idp;
while (1)
{
sleep(*id+2); // Thread work
pthread_mutex_lock(mutex);
threads_running++;
pthread_mutex_unlock(mutex);
pthread_cond_broadcast(cond);
printf("Thread %d WAIT\n", *id);
fflush(stdout);
// Let threads synchronize
pthread_mutex_lock(mutex);
while(threads_running != NUM_THREADS)
{
pthread_cond_wait(cond, mutex);
}
pthread_mutex_unlock(mutex);
printf("Thread %d WAKEUP\n", *id);
fflush(stdout);
// and continue
pthread_mutex_lock(mutex);
threads_running--;
pthread_mutex_unlock(mutex);
}
}
The thing that happens, is that some (usually #9 and one or two others) reach Thread %d WAKEUP but before the others can wake-up threads_running is already smaller than NUM_THREADS.
How can I synchronize multiple threads, so they continue together?
I am having some trouble wrapping my head around the parallel accesses to variables.
I found the answer seconds later:
Change while(threads_running != NUM_THREADS) to while(threads_running != 0 && threads_running != NUM_THREADS)
Change threads_running--; to threads_running = 0;
Now it works perfectly.
I recommend using pthread_cond_signal() than pthread_cond_broadcast(cond);
So the code flow where while loop is exiting looks like below.
pthread_mutex_lock(mutex);
while(threads_running != 0 && threads_running != NUM_THREADS)
{
pthread_cond_wait(cond, mutex);
}
pthread_cond_signal(cond);
So the final code looks like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define NUM_THREADS 10
void* thread(void* idp);
int threads_running = 0;
pthread_mutex_t* mutex;
pthread_cond_t* cond;
int main(int args, char **argv)
{
pthread_mutex_t mutex_var;
pthread_cond_t cond_var;
mutex = &mutex_var;
cond = &cond_var;
pthread_mutex_init(mutex, NULL);
pthread_cond_init(cond, NULL);
pthread_t threads[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; i++)
{
printf("Creating Thread %d....\n", i);
int* id = malloc(sizeof(int));
*id = i;
if(0 != pthread_create(&threads[i], NULL, thread, (void *) id))
{
perror("Error while creating the threads");
exit(1);
}
}
for (int i = 0; i < NUM_THREADS; i++)
{
pthread_join(threads[i], NULL);
}
return 0;
}
void* thread(void* idp)
{
int* id = (int*) idp;
while (1)
{
sleep(*id+2); // Thread work
pthread_mutex_lock(mutex);
threads_running++;
pthread_mutex_unlock(mutex);
printf("Thread %d WAIT\n", *id);
fflush(stdout);
// Let threads synchronize
pthread_mutex_lock(mutex);
while(threads_running != 0 && threads_running != NUM_THREADS)
{
pthread_cond_wait(cond, mutex);
}
pthread_cond_signal(cond);
pthread_mutex_unlock(mutex);
printf("Thread %d WAKEUP\n", *id);
fflush(stdout);
// and continue
pthread_mutex_lock(mutex);
threads_running = 0;
pthread_mutex_unlock(mutex);
}
}
Related
I tried to make a parallel program that generates a random number with one thread and the other thread writes it.
Am I doing something wrong that messes with the performance/optimization? I ask it because it was very easy to write this program so I'm a little concerned that I am doing something wrong.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#include "produceConsume.h"
#define NUM_THREAD 1
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int queue[1];
int queueCounter = 0;
void *producer(void *args)
{
while (1)
{
pthread_mutex_lock(&lock);
int n = rand() % 100;
queue[queueCounter] = n;
queueCounter++;
pthread_cond_wait(&cond, &lock);
pthread_mutex_unlock(&lock);
}
}
void *consumer(void *args)
{
while (1)
{
pthread_mutex_lock(&lock);
printf("%d\n", queue[queueCounter - 1]);
queueCounter--;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
sleep(1);
}
}
int main()
{
system("clear");
srand(time(NULL));
pthread_t th[NUM_THREAD], th2[NUM_THREAD];
for (int i = 0; i < NUM_THREAD; i++)
{
pthread_create(&th[i], NULL, &producer, NULL);
pthread_create(&th2[i], NULL, &consumer, NULL);
}
for (int i = 0; i < NUM_THREAD; i++)
{
pthread_join(th[i], NULL);
pthread_join(th2[i], NULL);
}
}
You don't need an array if you are going to use only one thread, in any case, you create two threads but only one is joined (leaking memory), instead:
pthread_t th1[NUM_THREAD]; // or simply pthread_t th1;
pthread_t th2[NUM_THREAD]; // or simply pthread_t th2;
for (int i = 0; i < NUM_THREAD; i++)
{
pthread_create(&th1[i], NULL, &producer, NULL);
pthread_create(&th2[i], NULL, &consumer, NULL);
}
for (int i = 0; i < NUM_THREAD; i++)
{
pthread_join(th1[i], NULL);
pthread_join(th2[i], NULL);
}
I am writing various code snippets and see what happens. The code below was intended to delay all threads until all reached a certain point in the code and then make each print a distinctive number. Since the threads all do that, the numbers should occur in a random order.
My current problem is that I keep they threads busy waiting. If the number of threads gets big, the program slows down significantly.
I would like to change that by using signals, I found pthread_cond_wait() for that, however I don't see how one would use that to signal all threads that they would please wake up.
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#define threads 10
int counter=0;
pthread_mutex_t lock;
void handler(void *v) {
pthread_mutex_lock(&lock);
counter++;
printf("%d\n", counter);
pthread_mutex_unlock(&lock);
while(counter != threads); // busy waiting
printf("I am first! %d\n", v);
}
int main() {
pthread_t t[threads];
for(int i =0; i < threads; i++) {
pthread_create(&t[i], NULL, handler, (void*) i);
}
for(int i =0; i < threads; i++) {
pthread_join(t[i], NULL);
}
return 0;
}
EDIT: I changed the code to the following, however, it still does not work :/
pthread_mutex_t lock;
pthread_cond_t cv;
void handler(void *v) {
pthread_mutex_lock(&lock);
pthread_cond_wait(&cv, &lock);
printf("I am first! %d\n", v);
pthread_mutex_unlock(&lock);
}
int main() {
pthread_t t[threads];
for(int i =0; i < threads; i++)
pthread_create(&t[i], NULL, handler, (void*) i);
sleep(2);
pthread_cond_signal(&cv);
for(int i =0; i < threads; i++)
pthread_join(t[i], NULL);
return 0;
}
use broadcast()?
http://pubs.opengroup.org/onlinepubs/009696699/functions/pthread_cond_broadcast.html
The pthread_cond_broadcast() function shall unblock all threads currently blocked on the specified condition variable cond.
The pthread_cond_signal() function shall unblock at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond).
An alternative solution to pthread_cond_broadcast() might be the following.
You define a read-write mutex and lock it in write in the main thread before creating the other threads. The other threads will try to acquire a read-lock but since the main thread have a write-lock they will be blocked.
After the creation of all thread the main-thread releases the lock. All the other threads will be waken up and since many read-locks can coexist the will execute simultaneously (i.e. no one will be locked).
Code might be something like:
pthread_rwlock_t lock;
void handler(void *v) {
if ((res = pthread_rwlock_rdlock(&lock)!=0)
{
exit(1);
}
printf("I am first! %d\n", v);
pthread_rwlock_unlock(&lock);
}
int main() {
pthread_t t[threads];
//First acquire the write lock:
if ((res = pthread_rwlock_wrlock(&lock)!=0)
{
exit(1);
}
for(int i =0; i < threads; i++)
{
pthread_create(&t[i], NULL, handler, (void*) i);
//it is not clear if you want sleep inside the loop or not
// You indented it as if to be inside but not put brackets
sleep(2);
}
pthread_rwlock_unlock(&lock);
for(int i =0; i < threads; i++)
pthread_join(t[i], NULL);
pthread_rwlock_destroy(&lock);
return 0;
}
Try posting the matching remove_from_buffer code.
Better yet, Short, Self Contained, Correct Example
Make a short main() with two threads.
One thread adds to the buffer at random intervals.
The other thread removes from the buffer at random intervals.
Example
CELEBP22
/* CELEBP22 */
#define _OPEN_THREADS
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
pthread_cond_t cond;
pthread_mutex_t mutex;
int footprint = 0;
void *thread(void *arg) {
time_t T;
if (pthread_mutex_lock(&mutex) != 0) {
perror("pthread_mutex_lock() error");
exit(6);
}
time(&T);
printf("starting wait at %s", ctime(&T));
footprint++;
if (pthread_cond_wait(&cond, &mutex) != 0) {
perror("pthread_cond_timedwait() error");
exit(7);
}
time(&T);
printf("wait over at %s", ctime(&T));
}
main() {
pthread_t thid;
time_t T;
struct timespec t;
if (pthread_mutex_init(&mutex, NULL) != 0) {
perror("pthread_mutex_init() error");
exit(1);
}
if (pthread_cond_init(&cond, NULL) != 0) {
perror("pthread_cond_init() error");
exit(2);
}
if (pthread_create(&thid, NULL, thread, NULL) != 0) {
perror("pthread_create() error");
exit(3);
}
while (footprint == 0)
sleep(1);
puts("IPT is about ready to release the thread");
sleep(2);
if (pthread_cond_signal(&cond) != 0) {
perror("pthread_cond_signal() error");
exit(4);
}
if (pthread_join(thid, NULL) != 0) {
perror("pthread_join() error");
exit(5);
}
}
OUTPUT
starting wait at Fri Jun 16 10:54:06 2006 IPT is about ready to
release the thread wait over at Fri Jun 16 10:54:09 2006
I am writing a multi-threaded application that reads a file and seeks for a word in chunks of it a thread has in memory.
A thread needs to asynchronously close other threads looking for that word if it is first to find it.
The problem is when a word is found and other threads are being closed the program does not terminate (in 6 out of 10 executions). I have checked in gdb that one thread does not exit. It happens even when I do not call waitforthreads(n_threads).
// [...]
FILE* f;
pthread_mutex_t mutex;
pthread_t* threads;
int n_threads;
int allread;
// [...]
int main(int argc, char* argv[]) {
// [...]
threads = (pthread_t*) calloc(n_threads, sizeof(pthread_t));
pthread_mutex_init(&mutex, NULL);
runthreads(f, word, n_threads, n_records);
waitforthreads(n_threads);
pthread_mutex_destroy(&mutex);
// [...]
}
void runthreads(FILE* f, char* w, int n_threads, int n_records) {
struct targs_t args = {w, n_records};
for (int i=0; i<n_threads; i++)
pthread_create(&threads[i], NULL, findword, (void*) &args);
}
void waitforthreads(int N) {
for (int i=0; i<N; i++)
if(pthread_join(threads[i], NULL))
exit_(6);
}
void* findword(void* arg) {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
struct targs_t* args = (struct targs_t*) arg;
int max_length = args->n_records * sizeof(record_t);
record_t* records = malloc(max_length);
int found = 0;
while (!allread && !found) {
pthread_mutex_lock(&mutex);
// allread is being set in the function below
// if the whole file has been read
readRecords((char*) records, args->n_records, f);
pthread_mutex_unlock(&mutex);
for (int i=0; i<args->n_records; i++)
if (strlen(records[i].text) == 0) break;
else if (strstr(records[i].text, args->word) != NULL) {
notifyfound(pthread_self(), records[i].id);
found = 1;
break;
}
}
free(records);
return NULL;
}
void notifyfound(pthread_t tid, int id) {
printf("Found: %d (%ld)\n", id, (long) tid);
for (int i=0; i<n_threads; i++)
if (threads[i] && !pthread_equal(threads[i], tid)) {
printf(" closing %ld\n", (long) threads[i]);
pthread_cancel(threads[i]);
}
printf(" finished closing\n");
}
This has to do with cancellation points, although the specifics are hard to come by since you haven't shared a minimal example. My diagnosis is either
6/10 times you have at least one thread waiting for a mutex, and other one in readRecords, which will cancel and not free the mutex. Setup cancellation handlers with pthread_cleanup_push and pthread_cleanup_pop which will free your mutex, and read the manual for pthread_cancel. See related pthread_cleanup_push causes Syntax error for some references.
Some of your threads are not detecting the cancellation - try using pthread_testcancel to setup a guaranteed cancellation point.
Here is some code that fixes these sorts of problems, by adding a cancellation check and mutex cleanup.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
FILE* f;
pthread_mutex_t mutex;
pthread_t* threads;
int n_threads = 3;
int allread;
long int count = 0;
int *thread_ids;
int global_quit = 0;
#define MAX 99999
void waitforthreads(int N) {
printf("waiting for %d threads\n", N);
for (int i=0; i<N; i++)
{
printf("thread %d | %d\n", i, threads[i]);
if(pthread_join(threads[i], NULL))
{
printf("problem\n");
exit(6);
}
}
printf("done.\n");
}
void notifyfound(pthread_t tid, int count) {
printf("%d | %d got big number\n", count, pthread_self());
for (int i=0; i<n_threads; i++)
if (threads[i] && !pthread_equal(threads[i], tid)) {
printf(" closing '%ld'\n", (long) threads[i]);
pthread_cancel(threads[i]);
}
global_quit = 1;
printf(" finished closing\n");
}
void waiting_thread_cleanup(void *arg)
{
pthread_mutex_unlock((pthread_mutex_t *)arg);
}
void* do_thing(void* arg) {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
int* id = (int *)arg;
int quit = 0;
while (!allread) {
pthread_mutex_lock(&mutex);
pthread_cleanup_push(waiting_thread_cleanup, (void *)&mutex); /* must be paired with pop. */
if(count++==MAX)
{
notifyfound(pthread_self(), *id);
quit=1;
}
else if(count % 10000 == 0)
printf("[%d] - %d\n", *id, count);
pthread_testcancel(); /* required to allow for the cancel to ever be 'detected' other functions are sufficient as well. */
pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(1); /* if this isn't here, this will occassionally hand because the mutex isn't freed. */
if(quit==1)
{
printf("%d | %d quitting\n", *id, pthread_self());
break;
}
}
return NULL;
}
void runthreads(FILE* f, int n_threads) {
for (int i=0; i<n_threads; i++)
pthread_create(&threads[i], NULL, do_thing, &(thread_ids[i]));
}
int main(int argc, char* argv[]) {
threads = (pthread_t*) calloc(n_threads, sizeof(pthread_t));
thread_ids = (int*) calloc(n_threads, sizeof(int));
for(int i=0;i<n_threads;i++)
thread_ids[i] = i;
pthread_mutex_init(&mutex, NULL);
runthreads(f, n_threads);
waitforthreads(n_threads);
pthread_mutex_destroy(&mutex);
}
I wrote this code in order to better understand producer consumer in a program where I require threads to wait for a task and then work in parallel to complete it.
I am wondering if I really needed an array for the conditionMet integer variables?
Could I not do the same with one integer?
Was there anything I could do to simplify the code?
My goal is to allow the main thread to hand tasks to the other threads.
Since this is just the skeleton, I am wondering if there is a way to simplify it?
#define _MULTI_THREADED
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#define NTHREADS 7
#define RUN_N_TIMES 3
pthread_cond_t new_task_available = PTHREAD_COND_INITIALIZER;
pthread_cond_t task_complete = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
volatile int producerCond = 0;
volatile int conditionMet[NTHREADS] = {};
volatile int no_more_tasks = 0;
volatile int mini_tasks_complete = - NTHREADS;
void do_work(unsigned int* current_level){
++*current_level;
printf("Thread %u has completed %u units of work.\nIt was #%d to complete it's task this round..\n", (unsigned int)pthread_self(), *current_level, mini_tasks_complete);
}
void *threadfunc(void *parm)
{
int* thread_cond;
unsigned int level = 0;
thread_cond = (int*)parm;
while(!no_more_tasks){
pthread_mutex_lock(&mutex);
++mini_tasks_complete;
if(mini_tasks_complete == NTHREADS){
producerCond = 1;
pthread_cond_signal(&task_complete);
}
threads_waiting++;
*thread_cond = 0;
while (!*thread_cond) {
pthread_cond_wait(&new_task_available, &mutex);
if(no_more_tasks)
{
pthread_mutex_unlock(&mutex);
return NULL;
}
}
pthread_mutex_unlock(&mutex);
do_work(&level);
}
return NULL;
}
void reset_cond(int val){
int i;
for (i=0; i<NTHREADS; ++i)
conditionMet[i] = val;
}
int main(int argc, char **argv)
{
int i;
pthread_t threadid[NTHREADS];
for(i=0; i < NTHREADS; ++i) {
pthread_create(&threadid[i], NULL, threadfunc, &(conditionMet[i]));
}
while(threads_waiting < NTHREADS)
sleep(1); /* Sleep is not a very robust way to serialize threads */
/* The condition has occured. Set the flag and wake up any waiting threads */
printf("Waking up all waiting threads " "#RUN_N_TIMES" " times...\n");
for(i = 0; i < RUN_N_TIMES; i++){
pthread_mutex_lock(&mutex);
mini_tasks_complete = 0;
printf("New tasks available.\n");
sleep(1);
reset_cond(1);
pthread_cond_broadcast(&new_task_available);
producerCond = 0;
while (!producerCond) {
printf("Main waiting\n");
pthread_cond_wait(&task_complete, &mutex);
}
pthread_mutex_unlock(&mutex);
}
no_more_tasks = 1;
pthread_mutex_lock(&mutex);
mini_tasks_complete = 0;
printf("Go home everybody!\n");
pthread_cond_broadcast(&new_task_available);
pthread_mutex_unlock(&mutex);
printf("Wait for threads and cleanup\n");
for (i=0; i<NTHREADS; ++i) {
pthread_join(threadid[i], NULL);
}
pthread_cond_destroy(&new_task_available);
pthread_cond_destroy(&task_complete);
pthread_mutex_destroy(&mutex);
printf("Main done\n");
return 0;
}
I am trying to use pthread mutex variables and barrier to synchronize the output of my program, but it is not working the way I want it to. Each thread is seeing its final value every 20 values (coming from the for loop) which is alright but I'm trying to make them all get to the same final value (if using 5 threads, all of them should see 100 as final value, with 4 threads, 80, etc)
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int SharedVariable =0;
void *SimpleThread(void *args)
{
int num,val,rc;
int which =(int)args;
rc = pthread_mutex_lock(&mutex1);
for(num=0; num<20; num++){
#ifdef PTHREAD_SYNC
if(random() > RAND_MAX / 2)
usleep(10);
#endif
//pthread_mutex_lock(&mutex1);
val = SharedVariable;
printf("*** thread %d sees value %d\n", which, val);
//pthread_mutex_lock(&mutex1);
SharedVariable = val+1;
pthread_mutex_unlock(&mutex1);
}
val=SharedVariable;
printf("Thread %d sees final value %d\n", which, val);
//pthread_mutex_destroy(&mutex1);
//pthread_exit((void*) 0);
//pthread_mutex_unlock(&mutex1);
}
int main (int argc, char *argv[])
{
if(atoi(argv[1]) > 0){
int num_threads = atoi(argv[1]);
//pthread_mutex_init(&mutex1, NULL);
pthread_t threads[num_threads];
int rc;
long t;
rc = pthread_mutex_lock(&mutex1);
for(t=0; t< num_threads; t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, SimpleThread, (void* )t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
//pthread_join(thread1);
}
rc= pthread_mutex_unlock(&mutex1);
}
else{
printf("ERROR: The parameter should be a valid positive number.");
exit(-1);
}
pthread_mutex_destroy(&mutex1);
pthread_exit(NULL);
}
Any suggestions or help is greatly appreciated!
Thanks in advanced!
You need to use a barrier (pthread_barrier_wait()) before checking for the final value - this ensures that no thread will proceed until all threads have reached the barrier.
In addition, you should be calling pthread_join() to wait for the threads to finish, and you only need to hold the mutex around the increment:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_barrier_t barrier1;
int SharedVariable = 0;
void *SimpleThread(void *args)
{
int num,val;
int which = (int)args;
for(num = 0; num < 20; num++) {
#ifdef PTHREAD_SYNC
if(random() > RAND_MAX / 2)
usleep(10);
#endif
pthread_mutex_lock(&mutex1);
val = SharedVariable;
printf("*** thread %d sees value %d\n", which, val);
SharedVariable = val + 1;
pthread_mutex_unlock(&mutex1);
}
pthread_barrier_wait(&barrier1);
val = SharedVariable;
printf("Thread %d sees final value %d\n", which, val);
return 0;
}
int main (int argc, char *argv[])
{
int num_threads = argc > 1 ? atoi(argv[1]) : 0;
if (num_threads > 0) {
pthread_t threads[num_threads];
int rc;
long t;
rc = pthread_barrier_init(&barrier1, NULL, num_threads);
if (rc) {
fprintf(stderr, "pthread_barrier_init: %s\n", strerror(rc));
exit(1);
}
for (t = 0; t < num_threads; t++) {
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, SimpleThread, (void* )t);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
for (t = 0; t < num_threads; t++) {
pthread_join(threads[t], NULL);
}
}
else {
printf("ERROR: The parameter should be a valid positive number.\n");
exit(-1);
}
return 0;
}
Try to move the pthread_mutext_unlock(&mutext1) out of the for loop in your SimpleThread. You lock once and unlock mutiple(20) times in your original code.
Alternatively, you could move pthread_mutex_lock(&mutext1) into the for loop, just before you read and modify your SharedVariable. In this case, each thread's add-by-one operation may not consecutive but each thread will get the correct final value.
And before you read the final value of the SharedVariable, use a barrier to wait all the threads finish their job.