im trying to implement a multi threading with multible threads (user can enter number of workers = threads when starting the programm) where each thread calling functionA and afterwards functionB. But before functionB should only be executed after ALL threads have called functionA. Thats my pseudo code:

void* worker_do(void* worker_id)
{
  functionA((size_t) worker_id);
  // First thread should only start functionB after ALL threads
  // are finished with functionA
  functionB((size_t) worker_id);
  return NULL;
}

// I am not allowed to change pthread_create and pthread_join here
int main()
{
  // should be a flexible value
  ssize_t num_workers = 20;
  pthread_t* workers  = malloc(num_workers*sizeof(pthread_t));

  for(ssize_t i = 0; i < num_workers; i++)
    pthread_create(&workers[i], NULL, worker_do, (void*) i);

  for(ssize_t i = 0; i < num_workers; i++)
    pthread_join(workers[i], NULL);

  free(workers);

  return 0;
}

I googled and found the possiblity of "condition variables". But I am not sure show they have to implemented for the condition

IF last_thread_has_called_functionA THEN start_calling_fuctionB

Or are condition variables not the right instrument to solve this issue?

Would really appreciate tipps how i can implement that...

bw Robert

2 Answers

0
WhozCraig On Best Solutions

Since you asked, to do this with a condition-variable and mutex, you could so something like this:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <inttypes.h>

#define N_THREADS   10

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
unsigned int count = 0;

void functionA(intptr_t id)
{
    printf("functionA: %" PRIdPTR "\n", id);
}

void functionB(intptr_t id)
{
    printf("functionB: %" PRIdPTR "\n", id);
}

void* thread_proc(void* pv)
{
    intptr_t id = (intptr_t)pv;

    functionA(id);

    // lock the mutex to protect the predicate data (count)
    pthread_mutex_lock(&mtx);
    ++count;
    pthread_cond_broadcast(&cv);

    // wait for all threads to finish A
    while (count < N_THREADS)
        pthread_cond_wait(&cv, &mtx);

    // this is still owned by us. release it.
    pthread_mutex_unlock(&mtx);

    // now B
    functionB(id);

    return NULL;
}

int main()
{
    pthread_t thrds[N_THREADS];
    for (int i=0; i<N_THREADS; ++i)
        pthread_create(thrds+i, NULL, thread_proc, (void*)(intptr_t)(i+1));

    for (int i=0; i<N_THREADS; ++i)
        pthread_join(thrds[i], NULL);

    return EXIT_SUCCESS;
}

Sample Output (varies)

functionA: 1
functionA: 4
functionA: 6
functionA: 3
functionA: 2
functionA: 8
functionA: 9
functionA: 7
functionA: 10
functionA: 5
functionB: 10
functionB: 9
functionB: 5
functionB: 7
functionB: 4
functionB: 6
functionB: 1
functionB: 2
functionB: 8
functionB: 3

That said, as Jonathan pointed out in general comment, a barrier is a more elegant solution to this issue. I would post an example, but alas my environment doesn't support them (sad, mac os x). They're available on most Unix pthread implementations, so if your target platform provides them, I suggest investigating them proper.

1
MayurK On

I assume functionA() and functionB() can be executed parallelly by threads as there is no mutex protection in your current code.

In order to address your problem, you can use simple polling mechanism. After execution of functionA(), each thread will increment a counter. All threads will wait until the counter becomes equal to number of threads created.

For this approach, you need to have a mutex and a counter common across all threads. For simplicity of the code, I am using a global variable.

unsigned int num_threads = 0;
unsigned int num_threads_completed_functionA = 0;
pthread_mutex_t lock;

void* worker_do(void* worker_id)
{
  functionA((size_t) worker_id);
  // First thread should only start functionB after ALL threads are finished with functionA

  //Lock the mutex and update the counter
  pthread_mutex_lock(&lock);
  num_threads_completed_functionA++;
  pthread_mutex_unlock(&lock);

  while(1)
  {
    //Lock mutex and check how many threads completed execution of functionA()
    pthread_mutex_lock(&lock);
    if(num_threads_completed_functionA == num_threads)
    {
       //If all threads completed, then break the loop and proceed executing functionB()
       pthread_mutex_unlock(&lock);
       break;
    }
    pthread_mutex_unlock(&lock);
    usleep(1); //Sleep for some time
  }

  //ALL threads are finished with functionA
  functionB((size_t) worker_id);
  return NULL;
}