0
votes

I have three integers (a, b and c), and I'd like to create two threads (POSIX pthreads) to access them in this particular sequence to keep the results consistent:

Thread 1  |  Thread 2
---------------------
a=1          b=5
c=7
             c=c+10
             b=a+c*2
a=b+b*10

That is, c=c+10 in thread2 must wait until c=7 in thread1 finishes. Also a=b+b*10 in thread1 must wait until b=a+c*2 in thread2 finished.

I have tried using mutexes, but it does not work as I intend (code below). If thread2 starts first, it can lock mutex1 before thread1 has locked it, so the sequencing is lost. Locking the mutex from the main thread is not an option, as it would yield an undefined behavior (mutex locked and then unlocked by a different thread). I've also tried using conditional variables, but a similar problem arises: a signal can happen before the associated wait.

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

int a, b, c;
pthread_mutex_t mutex1, mutex2 = PTHREAD_MUTEX_INITIALIZER;

void *thread1(void *arg) {
    pthread_mutex_lock(&mutex1);
    a = 1;
    c = 7; 
    pthread_mutex_unlock(&mutex1);
    pthread_mutex_lock(&mutex2);
    a = b + b*10; 
    pthread_exit(NULL);
}

void *thread2(void *arg) {
    pthread_mutex_lock(&mutex2);
    b = 5;
    pthread_mutex_lock(&mutex1);
    c = c + 10;
    b = a + c*2;
    pthread_mutex_unlock(&mutex2);
    pthread_exit(NULL);
}

int main() {
    pthread_t t1, t2;

    if(pthread_create(&t1, NULL, thread1, NULL)) {
        fprintf(stderr, "Error creating Thread 1\n");
        return 0;
    }
    if(pthread_create(&t2, NULL, thread2, NULL)) {
        fprintf(stderr, "Error creating Thread 2\n");
        return 0;
    }

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    return a;
}

My question is, what is correct way to achieve the thread sequencing I want using pthreads? Thanks in advance.

1
Shouldn't these int a, b, c; variables be volatile? - Gaurav Pathak
@usr I simplified the code here, the real code has bigger chunks that execute in parallel - Juan M Rivas
Without even looking in depth, 2 mutexes for one synchronisation job seem fishy. - spectras
The usual: a) serializing two threads is pointless b) Mutex is the wrong synchro for this, and I don't uderstand why so may peple keep trying it - it still doesn't work, every time. c) Use two semaphores. Swap around one 'execution permit' between the threads. - Martin James
You might want to read wikipedia's barrier article. - spectras

1 Answers

0
votes
pthread_mutex_t mutex1, mutex2 = PTHREAD_MUTEX_INITIALIZER

Only initializes the second one; but that is a nit. Depending upon the system you are running, you might not notice this, because mutex1 is uninitialized, thus the operations on it may be failing, or the initializer constant could be zero....

The signal/wait problem is not a problem -- you wait upon a condition protected by a mutex, in this pattern:

lock();
while (check() == false) {
    wait();
}
func();
signal();
unlock();

so thread1’s check would be true, and func would be c = 7 while thread2’s check would be (c == 7) and func would be c += 10