How to make a pthread signal another that it can continue executing? - c

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.

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

Related

Understanding concurrency better (with locks)

I'm trying to understand concurrency and using locks better, but this dummy example I made is throwing me off:
int i = 0;
void foo() {
int n = i;
i = i + 1;
printf("foo: %d\n", n);
}
void boo() {
int n = i;
i = i + 1;
printf("boo: %d\n", n);
}
int main(int argc, char* argv[]) {
pthread_t p1, p2;
pthread_create(&p1, NULL, (void*) foo, NULL);
pthread_create(&p2, NULL, (void*) boo, NULL);
// wait for threads to finish
pthread_join(p1, NULL);
pthread_join(p2, NULL);
// final print
printf("main: %d\n", i);
return 0;
}
If I understand correctly, the i = i + 1; in both foo() and bar() can cause some unexpected behaviour. One unexpected behaviour is that we'll get both "foo: 0" and "bar: 0" since it's possible that a context switch happened right before the i = i + 1; and so n is always 0. I think the expected behaviour is that "foo: 0" "bar: 1" or "bar: 0" "foo: 1" (please correct me if I'm wrong).
To fix this, I added locks:
int i = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void foo() {
int n = i;
i = i + 1;
printf("foo: %d\n", n);
}
void boo() {
int n = i;
i = i + 1;
printf("boo: %d\n", n);
}
int main(int argc, char* argv[]) {
pthread_t p1, p2;
printf("Locking foo\n");
pthread_mutex_lock(&lock);
printf("Locked foo\n");
pthread_create(&p1, NULL, (void*) foo, NULL);
pthread_mutex_unlock(&lock);
printf("Unlocked foo\n");
printf("Locking boo\n");
pthread_mutex_lock(&lock);
printf("Locked boo\n");
pthread_create(&p2, NULL, (void*) boo, NULL);
pthread_mutex_unlock(&lock);
printf("Unlocked boo\n");
// wait for threads to finish
pthread_join(p1, NULL);
pthread_join(p2, NULL);
// final print
printf("main: %d\n", i);
return 0;
}
I think this would fix the unexpected results, but I got a surprising output when I ran this:
Locking foo
Locked foo
Unlocked foo
Locking boo
Locked boo
foo: 0
Unlocked boo
boo: 1
main: 2
It looks like the program locked the first thread that calls foo() and then immediately unlocked it without actually executing the printf? It then goes on to locking the thread that calls boo() and does weird things out of order. Can someone explain this behaviour? I would of thought the output would have looked like:
Locking foo
Locked foo
foo: 0
Unlocked foo
Locking boo
Locked boo
boo: 1
Unlocked boo
main: 2
Your choice of wording betrays a likely serious misunderstanding:
It looks like the program locked the first thread that calls foo()
Programs do not lock threads. Rather, threads acquire locks (or, equivalently, threads lock mutexes). That can include a program's main thread, too. Mutual exclusion is achieved among cooperating (!) threads by the fact that only one thread can hold any particular lock (mutex) at a time.
Thus, if thread B has a given mutex locked when thread A attempts to acquire it then thread A's acquisition attempt will block (the return of the pthread_mutex_lock() call will be delayed). Thread A will not proceed until it does acquire the mutex. Thus, the boundaries of critical regions are defined by calls to pthread_mutex_lock() and pthread_mutex_unlock() on the same mutex. Approximately speaking, every participating thread must acquire the appropriate mutex before accessing shared shared variables, and each one must release the mutex when it is done to allow other threads to acquire it in turn.
Other answers have already presented details of how that might look in your example program.
The locking should take place in the functions like here:
#include <stdio.h>
#include <pthread.h>
int i = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void foo() {
printf("Locking foo\n");
pthread_mutex_lock(&lock);
printf("Locked foo\n");
int n = i;
i = i + 1;
pthread_mutex_unlock(&lock);
printf("Unlocked foo\n");
printf("foo: %d\n", n);
}
void boo() {
printf("Locking boo\n");
pthread_mutex_lock(&lock);
printf("Locked boo\n");
int n = i;
i = i + 1;
pthread_mutex_unlock(&lock);
printf("Unlocked boo\n");
printf("boo: %d\n", n);
}
int main(int argc, char* argv[]) {
pthread_t p1, p2;
pthread_create(&p1, NULL, (void*) foo, NULL);
pthread_create(&p2, NULL, (void*) boo, NULL);
// wait for threads to finish
pthread_join(p1, NULL);
pthread_join(p2, NULL);
// final print
printf("main: %d\n", i);
return 0;
}
This way, when one function locks, the other function will be blocked until the lock is unlocked.
You are using the locks incorrectly. You lock the mutex, start the thread, and unlock it. The thread runs without any knowledge of the locking operations. Use the lock in the functions sharing memory:
void foo() {
pthread_mutex_lock(&lock);
int n = i;
i = i + 1;
pthread_mutex_unlock(&lock);
printf("foo: %d\n", n);
}
Do the same with boo function.

Why some threads don't receive pthread_cond_broadcast?

I have a threadpool of workers. Each worker executes this routine:
void* worker(void* args){
...
pthread_mutex_lock(&mtx);
while (queue == NULL && stop == 0){
pthread_cond_wait(&cond, &mtx);
}
el = pop(queue);
pthread_mutex_unlock(&mtx);
...
}
main thread:
int main(){
...
while (stop == 0){
...
pthread_mutex_lock(&mtx);
insert(queue, el);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx);
...
}
...
}
Then I have a signal handler that executes this code when it receives a signal:
void exit_handler(){
stop = 1;
pthread_mutex_lock(&mtx);
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mtx);
}
I have omitted declarations and initialization, but the original code has them.
After a signal is received most of the time it's all ok, but sometimes it seems that some worker threads stay in the wait loop because they don't see that the variable stop is changed and/or they are not waken up by the broadcast.
So the threads never end.
What I am missing?
EDIT: stop=1 moved inside the critical section in exit_handler. The issue remains.
EDIT2: I was executing the program on a VM with Ubuntu. Since the code appears to be totally right I tried to change VM and OS (XUbuntu) and now it seems to work correctly. Still don't know why, anyone has an idea?
Some guessing here, but it's too long for a comment, so if this is wrong, I will delete. I think you may have a misconception about how pthread_cond_broadcast works (at least something I've been burned with in the past). From the man page:
The pthread_cond_broadcast() function shall unblock all threads
currently blocked on the specified condition variable cond.
Ok, that make sense, _broadcast awakens all threads currently blocked on cond. However, only one of the awakened threads will then be able to lock the mutex after they're all awoken. Also from the man page:
The thread(s) that are unblocked shall contend for the mutex according
to the scheduling policy (if applicable), and as if each had called
pthread_mutex_lock().
So this means that if 3 threads are blocked on cond and _broadcast is called, all 3 threads will wake up, but only 1 can grab the mutex. The other 2 will still be stuck in pthread_cond_wait, waiting on a signal. Because of this, they don't see stop set to 1, and exit_handler (I'm assuming a Ctrl+c software signal?) is done signaling, so the remaining threads that lost the _broadcast competition are stuck in limbo, waiting on a signal that will never come, and unable to read that the stop flag has been set.
I think there are 2 options to work-around/fix this:
Use pthread_cond_timedwait. Even without being signaled, this will return from waiting at the specified time interval, see that stop == 1, and then exit.
Add pthread_cond_signal or pthread_cond_broadcast at the end of your worker function. This way, right before a thread exits, it will signal the cond variable allowing any other waiting threads to grab the mutex and finish processing. There is no harm in signaling a conditional variable if no threads are waiting on it, so this should be fine even for the last thread.
EDIT: Here is an MCVE that proves (as far as I can tell) that my answer above is wrong, heh. As soon as I press Ctrl+c, the program exits "immediately", which says to me all the threads are quickly acquiring the mutex after the broadcast, seeing that stop is false, and exiting. Then main joins on the threads and it's process over.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#define NUM_THREADS 3
#define STACK_SIZE 10
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
volatile bool stop = false;
int stack[STACK_SIZE] = { 0 };
int sp = 0; // stack pointer,, also doubles as the current stack size
void SigHandler(int sig)
{
if (sig == SIGINT)
{
stop = true;
}
else
{
printf("Received unexcepted signal %d\n", sig);
}
}
void* worker(void* param)
{
long tid = (long)(param);
while (stop == false)
{
// acquire the lock
pthread_mutex_lock(&m);
while (sp <= 0) // sp should never be < 0
{
// there is no data in the stack to consume, wait to get signaled
// this unlocks the mutex when it is called, and locks the
// mutex before it returns
pthread_cond_wait(&c, &m);
}
// when we get here we should be guaranteed sp >= 1
printf("thread %ld consuming stack[%d] = %d\n", tid, sp-1, stack[sp-1]);
sp--;
pthread_mutex_unlock(&m);
int sleepVal = rand() % 10;
printf("thread %ld sleeping for %d seconds...\n", tid, sleepVal);
sleep(sleepVal);
}
pthread_exit(NULL);
}
int main(void)
{
pthread_t threads[NUM_THREADS];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
srand(time(NULL));
for (long i=0; i<NUM_THREADS; i++)
{
int rc = pthread_create(&threads[i], &attr, worker, (void*)i);
if (rc != 0)
{
fprintf(stderr, "Failed to create thread %ld\n", i);
}
}
while (stop == false)
{
// produce data in bursts
int numValsToInsert = rand() % (STACK_SIZE - sp);
printf("main producing %d values\n", numValsToInsert);
// acquire the lock
pthread_mutex_lock(&m);
for (int i=0; i<numValsToInsert; i++)
{
// produce values for the stack
int val = rand() % 10000;
// I think this should already be guaranteed..?
if (sp+1 < STACK_SIZE)
{
printf("main pushing stack[%d] = %d\n", sp, val);
stack[sp++] = val;
// signal the workers that data is ready
//printf("main signaling threads...\n");
//pthread_cond_signal(&c);
}
else
{
printf("stack full!\n");
}
}
pthread_mutex_unlock(&m);
// signal the workers that data is ready
printf("main signaling threads...\n");
pthread_cond_broadcast(&c);
int sleepVal = 1;//rand() % 5;
printf("main sleeping for %d seconds...\n", sleepVal);
sleep(sleepVal);
}
for (long i=0; i<NUM_THREADS; i++)
{
pthread_join(threads[i], NULL);
}
return 0;
}

c - running 2 threads in parallel with a shared variable

Just a beginner to threads, I'm just doing a task which involves these 2 threads.
#include <stdio.h>
#include <pthread.h>
int count = 0;
void waitFor(unsigned int secs)
{
unsigned int retTime = time(0) + secs;
while(time(0) < retTime);
}
void func1(void * args)
{
printf("In func1 ...\n");
long i = 0;
while(1){
i++;
if(count == 1)
break;
}
printf("The total number counted is: %ld \n", i);
count = 0;
i = 0;
}
void func2(void * args)
{
printf("In func2 ...\n");
waitFor(3);
count = 1;
}
int main()
{
pthread_t th1, th2;
int j = 0;
while(j++ < 4){
printf("\nRound:\t%d\n", j);
pthread_create(&th1, NULL, (void*)func1,NULL);
pthread_create(&th2, NULL, (void*)func2, NULL);
pthread_join(th1,NULL);
pthread_join(th2,NULL);
waitFor(3);
}
return 0;
}
I've read various references and to my understanding pthread_join() means that if there are 2 or more threads, then they will wait for one thread to finish its execution and then next one will start executing and so on.
But when i run this program, the moment pthread_join(th1) is executed, both threads are created and executed 'concurrently'. How is this happening?
Output:
Round: 1
In func2 ...
In func1 ...
The total number counted is: 897651254
Round: 2
In func1 ...
In func2 ...
The total number counted is: 1051386065
........
My goal is to run these 2 threads in parallel. For now, join seems to do this; or am I going wrong somewhere?
And I've read that using volatile is not preferred for threads in C. So is there any way I could use count as a signal from thread 2 to 1?
Quote:
my understanding pthread_join() means that if there are 2 or more threads, then they will wait for one thread to finish its execution and then next one will start executing and so on
That is incorrect. Join simply means that the process waits until the thread has terminated.
Quote:
the moment pthread_join(th1) is executed, both threads are created and executed 'concurrently'.
That is incorrect. The threads are created and start when calling pthread_create Note: By start I mean that they are ready to execute. However, it is the OS that decides when they actually get to execute so it may take some time before they execute.
To share count between two threads you can use a mutex.
int count = 0;
pthread_mutex_t lock;
When accessing count you must first lock the mutex, read/write the variable and unlock the mutex.
Example:
pthread_mutex_lock(&lock);
count = 1;
pthread_mutex_unlock(&lock);
Example:
long i = 0;
while(1)
{
... code not using count ....
pthread_mutex_lock(&lock);
if(count == 1)
{
pthread_mutex_unlock(&lock);
break;
}
pthread_mutex_unlock(&lock);
... code not using count ....
}
And in main you'll need to initialize the mutex like:
pthread_mutex_init(&lock,NULL);

Changing the function that a thread executes

I'm implementing the Dining Philosophers problem in c using pthreads.
Each philosopher is represented by a thread.
Each thread needs to be able to execute four different functions.
I'm aware that I can set a thread to execute a function with:
pthread_create(&tid, &atr, func1, NULL);
That's fine, but how do I make the thread execute a different function later on (i.e. func2).
Is there a way to change the function that a thread is executing or am I off the ball entirely?
Thanks
Here's a possibility, demonstrated with a single thread (aside from the main thread).
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int to_run = 0;
void func0() {
to_run = -1;
while (to_run == -1) putchar('-');
}
void func1() {
to_run = -1;
while (to_run == -1) putchar('*');
}
void *func(void *data) {
while (1) {
switch (to_run) {
case 0:
func0();
break;
case 1:
func1();
break;
case 2:
printf("\nDONE\n");
return NULL;
}
}
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, func, NULL);
int i;
for (i=0; i<3; i++) {
sleep(1);
to_run = 1;
sleep(1);
to_run = 0;
}
to_run = 2;
pthread_join(tid, NULL);
return 0;
}
You shouldn't need to change the function the thread is running. You should represent each philosopher with a thread (as you said) and each fork with a mutex.
The philosopher threads will simply run a loop of 2 functions think then eat.
think is just a call to sleep.
eat will try to acquire the 2 mutexes that represent his adjacent forks. The philosopher thread will be blocked waiting for the mutexes to unlock. once they unlock then he can lock them himself (pickup_forks) and wait a short period of time (sleep) then unlock them (return_forks).
There is more to it than that, but it should get you past your current problem.
If your program freezes on a mutex lock. Its a deadlock and you may have to revise your algorithm to stop the deadlock.

pthread_cond_wait for 2 threads

I'm trying to implement pthread_cond_wait for 2 threads. My test code is trying to use two threads to preform the following scenario:
Thread B waits for condition
Thread A prints "Hello" five times
Thread A signals thread B
Thread A waits
Thread B prints "Goodbye"
Thread B signals thread A
Loop to start (x5)
So far the code prints "Hello" five times and then gets stuck. From examples I've looked at it seems I'm on the right track, "Lock mutex, wait, get signaled by other thread, unlock mutex, do stuff, loop"
Test Code:
//Import
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
//global variables
pthread_cond_t condA = PTHREAD_COND_INITIALIZER;
pthread_cond_t condB = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *threadA()
{
int i = 0, rValue, loopNum;
while(i<5)
{
//unlock mutex
rValue = pthread_mutex_unlock(&mutex);
//do stuff
for(loopNum = 1; loopNum <= 5; loopNum++)
printf("Hello %d\n", loopNum);
//signal condition of thread b
rValue = pthread_cond_signal(&condB);
//lock mutex
rValue = pthread_mutex_lock(&mutex);
//wait for turn
while( pthread_cond_wait(&condA, &mutex) != 0 )
i++;
}
}
void *threadB()
{
int n = 0, rValue;
while(n<5)
{
//lock mutex
rValue = pthread_mutex_lock(&mutex);
//wait for turn
while( pthread_cond_wait(&condB, &mutex) != 0 )
//unlock mutex
rValue = pthread_mutex_unlock(&mutex);
//do stuff
printf("Goodbye");
//signal condition a
rValue = pthread_cond_signal(&condA);
n++;
}
}
int main(int argc, char *argv[])
{
//create our threads
pthread_t a, b;
pthread_create(&a, NULL, threadA, NULL);
pthread_create(&b, NULL, threadB, NULL);
pthread_join(a, NULL);
pthread_join(b,NULL);
}
A pointer in the right direction would be greatly appreciated, thanks!
(Code compiled on Linux using "gcc timeTest.c -o timeTest -lpthread")
You have two problems. The first is that you aren't using while() loops correctly - for example, here:
//wait for turn
while( pthread_cond_wait(&condA, &mutex) != 0 )
i++;
The body of the while loop is the statement i++ - this will execute pthread_cond_wait() and i++ until the pthread_cond_wait() returns an error, so this is essentially an endless loop.
The second is that you can't use a pthreads condition variable on its own - it needs to be paired with some actual shared state (at its simplest, this shared state might just be a flag variable protected by a mutex). The pthread_cond_wait() function is used to wait for the shared state to reach a certain value, and the pthread_cond_signal() function is used when a thread has altered the shared state. Reworking your example to use such a variable:
//global variables
/* STATE_A = THREAD A runs next, STATE_B = THREAD B runs next */
enum { STATE_A, STATE_B } state = STATE_A;
pthread_cond_t condA = PTHREAD_COND_INITIALIZER;
pthread_cond_t condB = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *threadA()
{
int i = 0, rValue, loopNum;
while(i<5)
{
/* Wait for state A */
pthread_mutex_lock(&mutex);
while (state != STATE_A)
pthread_cond_wait(&condA, &mutex);
pthread_mutex_unlock(&mutex);
//do stuff
for(loopNum = 1; loopNum <= 5; loopNum++)
printf("Hello %d\n", loopNum);
/* Set state to B and wake up thread B */
pthread_mutex_lock(&mutex);
state = STATE_B;
pthread_cond_signal(&condB);
pthread_mutex_unlock(&mutex);
i++;
}
return 0;
}
void *threadB()
{
int n = 0, rValue;
while(n<5)
{
/* Wait for state B */
pthread_mutex_lock(&mutex);
while (state != STATE_B)
pthread_cond_wait(&condB, &mutex);
pthread_mutex_unlock(&mutex);
//do stuff
printf("Goodbye\n");
/* Set state to A and wake up thread A */
pthread_mutex_lock(&mutex);
state = STATE_A;
pthread_cond_signal(&condA);
pthread_mutex_unlock(&mutex);
n++;
}
return 0;
}
Note that the use of two condition variables condA and condB is unnecessary here - the code would be just as correct if only one condition variable was used instead.
The code actually works almost fine on my machine when you add curly braces to the while loop.
Adding to what caf said, you'll enter an infinite loop when threadB is started after threadA has already sent the condB signal hence why you need to use a shared state in your while loop.
You can introduce artifical delay using usleep(1) on line 47 and see for yourself.

Resources