1

Consider the following program:

// Compilation: 
// gcc -Wall -Wextra -pedantic -Wno-unused-parameter -O3 test.c -o test -pthread

// Include
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

// Common variables
sem_t sem;                      // Semaphore
static const int nthr = 4;      // Number of threads
static int n = 0;               // Global counter

// Wait for a given number of seconds
void wait(unsigned int seconds) 
{
    unsigned int limit = time(NULL) + seconds;
    while (time(NULL) < limit);
}

// Function f0
void* f0(void* arg)
{
    while (n < 2); // Here
    // Doing stuff that does no require any access to shared variable
    printf("...doing stuff in f0...\n");
    pthread_exit(NULL);
}

// Function fn
void* fn(void* arg)
{
    sem_wait(&sem);
    wait(1);
    printf("entering fn: n = %d\n", n);
    n++;
    printf("leaving fn: n = %d\n", n);
    wait(1);
    sem_post(&sem);
    pthread_exit(NULL);
}

// Main
int main(int argc, char* argv[])
{
    pthread_t thr[nthr];
    sem_init(&sem, 0, 1);
    pthread_create(&thr[0], NULL, f0, NULL);
    for (int i = 1; i < nthr; ++i) pthread_create(&(thr[i]), NULL, fn, NULL);  
    for (int i = 0; i < nthr; ++i) pthread_join(thr[i], NULL);
    return 0;
}

The program does the following: thread0 executes f0 while the other threads are executing fn. I would like f0 to wait until two threads have incremented n before doing something.

Currently line marked Here should do that, but it does not work. How to do it properly (using semaphores instead of mutexes when possible)?

Vincent
  • 57,703
  • 61
  • 205
  • 388
  • 1
    You can use pthread_cond_t. – Jazzwave06 Nov 18 '16 at 20:30
  • 1
    Yes, use `pthread_cond_wait` using a mutex. When every the condition is signaled, you should read `n` and check if you should continue. – Jens Munk Nov 18 '16 at 20:34
  • @JensMunk How to use it in the present case? – Vincent Nov 18 '16 at 21:02
  • Look here. http://stackoverflow.com/questions/16522858/understanding-of-pthread-cond-wait-and-pthread-cond-signal It explains how to use `pthread_cond_wait` - hold the mutex when increasing your loop count `n`. – Jens Munk Nov 18 '16 at 21:54

1 Answers1

0

You can use a pthread_cond, as mentioned in the comments:

https://linux.die.net/man/3/pthread_cond_init

IMO cond is a bit more complicated, so if you are starting in the multithread world, I would recommend to first use a mutex_lock:

http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_lock.html

In this case, you should use two locks, one you for the f0 function (f0_lock), and the other for reading / writing in the "n" (var_n_lock) variable. Your program should:

  1. Start with f0_lock locked and var_n_lock unlocked.
  2. f0 will wait for f0_lock.
  3. fn threads will do what they need to do, then lock var_n_lock, increase n by 1 and check if n == 2, if so unlock f0_lock and, finally, unlock var_n_lock.
  4. when n == 2 and the thread running f0 will be unlocked and keep running.

Just a couple things I noticed: it seems to me that the fn threads will be finished before f0, if that is the case, you should invert the order of your joins, it will result in a small optimization. Also, if you want your program to wait some time, use sleep or usleep, it will save you a lot of CPU.

Hope this helps.

Fernando Coelho
  • 237
  • 1
  • 8