Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding parallel thread execution

Writing simple C code, trying to control output from two different threads:

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>

sem_t sem;

void* thread_func(void* aArgs)
{
  printf("Entering thread %p with %d\n", (void*)pthread_self(), (int)aArgs);
  int i = 0;
  for(;i < 10; i++)
  {
    sem_wait(&sem);
    if ((i % 2) == (int)aArgs)
      printf("val is %d in thread %p \n", i, (void*)pthread_self());
    sem_post(&sem);
  }
}

int main()
{
  pthread_t thread_1, thread_2;

  sem_init(&sem, 0, 1);

  pthread_create(&thread_1, NULL, (void*)thread_func, (void*)0);
  pthread_create(&thread_2, NULL, (void*)thread_func, (void*)1);

  pthread_join(thread_1, NULL);
  pthread_join(thread_2, NULL);

  sem_destroy(&sem);

  return 0;
}

What i want to achieve, is sequence of intermixed odd and even numbers. But i receive all the numbers from one thread then all another numbers from the second thread, like this (even if i increase loop counter magnitude):

Entering thread 0xb75f2b40 with 0
val is 0 in thread 0xb75f2b40 
val is 2 in thread 0xb75f2b40 
val is 4 in thread 0xb75f2b40 
val is 6 in thread 0xb75f2b40 
val is 8 in thread 0xb75f2b40 
Entering thread 0xb6df1b40 with 1
val is 1 in thread 0xb6df1b40 
val is 3 in thread 0xb6df1b40 
val is 5 in thread 0xb6df1b40 
val is 7 in thread 0xb6df1b40 
val is 9 in thread 0xb6df1b40

The question is why two independent threads behave like they were two sequential tasks? Why the second thread didn't take the execution control until the first were not finished all the stuff?

I've tried to add pthread_yield() to the end of the for-loop, but situation doesn't change significantly: sometimes i get expected output, sometimes - as described above.

UPD. How can i achieve deterministic one-by-one thread execution? Is there any synchronisation primitive for this?

like image 481
ars Avatar asked Mar 17 '23 23:03

ars


1 Answers

If you want to get the desired output, you should use two semaphores instead of one. Each thread should wait on its own semaphore and post the other thread's semaphore after it is done with each loop iteration. The main thread can create one semaphore with a value of 1 and the other with a value of zero to start things off right. This will force the two threads to run in an alternating sequence.

As the program is written currently, doing a sem_post followed by a sem_wait is likely to result in the same thread grabbing the semaphore right away (on a single cpu system). I'm surprised that pthread_yield doesn't help, but using two semaphores will guarantee correct ordering no matter what.

like image 85
JS1 Avatar answered Mar 19 '23 19:03

JS1