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);
Related
So i have this program that makes 2 threads and one of those adds 5 to the global variable number while the other substracts 5
int number = 0;
bool flag = true;
pthread_mutex_t mutex;
void* change_number(void *x) {
int num = *(int *)x;
if(flag) {
flag = false;
printf("hi from thread 1\n");
time_t now = time(NULL);
while(now + 1 > time(NULL)) {
pthread_mutex_lock(&mutex);
number += num;
pthread_mutex_unlock(&mutex);
}
}
else
{
printf("hi from thread 2\n");
time_t now2 = time(NULL);
while(now2 + 1 > time(NULL)) {
pthread_mutex_lock(&mutex);
number += num;
pthread_mutex_unlock(&mutex);
}
}
}
int main(int argc, char* argv[])
{
int id = fork();
if(id==0) {
int par1 = 5;
int par2 = -5; //-(rand() % 11);
pthread_t t1;
pthread_t t2;
pthread_mutex_init(&mutex, NULL);
printf("1) SUccess code: %d\n", pthread_create(&t1, NULL, change_number, (void *) &par1));
printf("2) Success code: %d\n", pthread_create(&t2, NULL, change_number, (void *) &par2));
pthread_join(t1, NULL);
printf("thread 1 finished\n");
pthread_join(t2, NULL);
printf("thread 2 finished\n");
printf("Final number is: %d\n", number);
}
pthread_mutex_destroy(&mutex);
wait();
return 0;
}
Judging from the prints, i think it runs as intended but the results are very inconsistent (also i would expect the number to be close zero since they add/substract the same value). Here are some outputs:
Final number is: 8272054
Final number is: -253453
Final number is: 3405063
Am i doing something wrong? Or the output depends on the specifics of my OS?
The biggest source of inconsistency in your results is the number of times you let each thread add/subtract to/from the global value. The now + 1 > time(NULL) style doesn't guarantee at all that both the threads would execute their respective loops for the same number of times since the threads being scheduled to execute their loops is independent from the progression of system time. Either of the threads might thus lose out on its shot at executing the loop. To make this more consistent and yield the expected 0, you could perhaps have something like
int count = 5000; // or whatever number you choose
while(count--) {
pthread_mutex_lock(&mutex);
number += num;
pthread_mutex_unlock(&mutex);
}
This ensures that the threads perform the operations an equal number of times irrespective of scheduling concerns and system time.
NOTE: There is a subtle bug in your program. It might so happen that both the threads handlers are executed at the same time and both see the value of flag as true and end up in the hi from thread 1 block. Of course, the value at the end would still be 0 since one is adding +5 and another -5 but this is probably not something you'd want. Try looking at other constructs (e.g. atomic_bool etc.)
A nitpick: Try having the call to wait(NULL) in the parent process rather than calling it from both the child and parent. The call from the child process would anyway exit with an error.
I want a routine to be done by multiple threads, once they are created they need their work to be all finished before copying their calculated things. So a thread is on cond_wait once it has its work done.
A piece of code that works now:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX_RAYCAST_THREADS 2
typedef struct s_thread_env
{
int id;
pthread_t thread;
int work_done;
void *shared_data;
} t_thread_env;
typedef struct s_shared_data
{
t_thread_env *tab_thread_env;
int max_thread;
int all_work_done;
pthread_mutex_t mutex;
pthread_cond_t cond;
int stop;
} t_shared_data;
void set_threads_again(int id, t_shared_data *shared_data)
{
int i;
shared_data->all_work_done = 0;
i = -1;
while (++i < shared_data->max_thread)
shared_data->tab_thread_env[i].work_done = 0;
//i = -1;
//while (++i < shared_data->max_thread)
//{
//if (i != id)
//{
//printf("cond_signal to thread %i\n", i);
//pthread_cond_signal(&shared_data->cond);
//}
//}
pthread_cond_broadcast(&shared_data->cond);
}
void wait_or_signal(t_thread_env *thread_env, t_shared_data *shared_data)
{
int i;
i = 0;
while (i < shared_data->max_thread && shared_data->tab_thread_env[i].work_done)
i++;
if (i == shared_data->max_thread)
{
printf(" allworkdone sent by thread %i\n", thread_env->id);
//printf(" copy_screenpixels() by thread %i\n", thread_env->id);
set_threads_again(thread_env->id, shared_data);
}
else
{
printf(" thread number %i is waiting for other threads\n", thread_env->id);
pthread_cond_wait(&shared_data->cond, &shared_data->mutex);
printf("ENFIN ! thread number %i woke up from condwait\n", thread_env->id);
}
}
void *routine(void *arg)
{
t_thread_env *thread_env;
t_shared_data *shared_data;
int stop;
thread_env = (t_thread_env *)arg;
shared_data = (t_shared_data *)thread_env->shared_data;
pthread_mutex_lock(&shared_data->mutex);
while (!shared_data->stop)
{
printf("new frame> thread_id = %i, thread_env->work_done = %i\n", thread_env->id, thread_env->work_done);
pthread_mutex_unlock(&shared_data->mutex);
printf(" raycast() in routine thread %i\n", thread_env->id);
pthread_mutex_lock(&shared_data->mutex);
thread_env->work_done++;
wait_or_signal(thread_env, shared_data);
}
pthread_mutex_unlock(&shared_data->mutex);
return (0);
}
void init_thread_env(t_shared_data *shared_data, int i)
{
t_thread_env *thread_env;
thread_env = &shared_data->tab_thread_env[i];
thread_env->id = i;
thread_env->shared_data = shared_data;
if (pthread_create(&thread_env->thread, NULL, routine, thread_env) != 0)
printf("Error pthread_create for %i\n", i);
}
void free_all(t_shared_data *shared_data)
{
int i;
pthread_mutex_lock(&shared_data->mutex);
shared_data->stop = 1;
pthread_mutex_unlock(&shared_data->mutex);
i = -1;
while (++i < shared_data->max_thread)
pthread_join(shared_data->tab_thread_env[i].thread, NULL);
printf("\nEND\n\n");
//free etc
}
int main()
{
int i;
t_shared_data *shared_data;
shared_data = (t_shared_data*)malloc(sizeof(t_shared_data)); // if (!shared data){free etc}
shared_data->max_thread = MAX_RAYCAST_THREADS;
pthread_mutex_init(&shared_data->mutex, 0);
pthread_cond_init(&shared_data->cond, 0);
shared_data->tab_thread_env = (t_thread_env*)malloc(sizeof(t_thread_env) * shared_data->max_thread);
i = -1;
while (++i < shared_data->max_thread)
init_thread_env(shared_data, i);
while (1)
sleep(1); //program is turning
free_all(shared_data);
return (0);
}
The correct output:
new frame> thread_id = 0, thread_env->work_done = 0
raycast() in routine thread 0
thread number 0 is waiting for other threads
new frame> thread_id = 1, thread_env->work_done = 0
raycast() in routine thread 1
allworkdone sent by thread 1
cond_signal to thread 0
new frame> thread_id = 1, thread_env->work_done = 0
ENFIN ! thread number 0 woke up from condwait
new frame> thread_id = 0, thread_env->work_done = 0
raycast() in routine thread 0
thread number 0 is waiting for other threads
raycast() in routine thread 1
allworkdone sent by thread 1
cond_signal to thread 0
new frame> thread_id = 1, thread_env->work_done = 0
ENFIN ! thread number 0 woke up from condwait
new frame> thread_id = 0, thread_env->work_done = 0
raycast() in routine thread 0
thread number 0 is waiting for other threads
raycast() in routine thread 1
Thank you for reading me, have a good day!
EDIT: I made a more readable and compilable version with only 1 mutex (old version: https://pastebin.com/4zMyBJi2).
EDIT2: deleted some parts of the original post, and tried to avoid every data races, my code still has some (as it still does not work). But I think I am close to get something working
EDIT3: Ok it is working now, I edited the code. The main issue was my disastrous use of the shared_data variables.
I tried to make my raycasting threads work using 1 call of
pthread_create for each thread (in an initialisation function). Is
it possible to do it?
Each successful call to pthread_create creates exactly one thread, so this is the only way to do it. But do not get confused between threads' start functions and threads themselves. Multiple threads can be created to run the same thread function, but this requires multiple calls to pthread_create, one for each thread.
I guess it is better (for performances) to do
it in this way (rather than an enormous amount of pthread_create and
pthread_join calls), is this correct?
Having chosen to use a certain number of threads to do certain pieces of work, the number of pthread_create calls is already determined. If you have performance concerns then they should be about how many threads to use, the details of the work they are to perform, and the nature and granularity of their synchronization.
In order to make it happen, the last thread (number n) to finish his
job has to tell the other ones that every thread has finished, so
there is a pthread_cond_wait for the (n - 1) first threads, and the
last thread (number n) calls pthread_cond_signal for each (n - 1)
first ones. Each thread has his own mutex.
That seems a little overkill, even if you can make it technically correct. It doesn't make much sense to have a mutex per thread, because mutexes are useful only when different threads use the same one. It may make sense to have different mutexes for protecting different shared resources, however. You would probably want CVs for some of those, but not all of them.
This appears to be (at least one area) where your code is failing. Your threads are not properly synchronized because they all rely on different mutexes to protect the same resources. It's not clear to me whether it makes sense for your program to have any more than just one mutex, but I would start by reducing your usage to that.
I'm really struggling with understanding how to lock and unlock mutexes in a way that lets threads run at the same time. Right now I'm trying to have every thread do something, then wait until all threads are ready, and then repeat it. This should happen repeatedly, so I have it all in a conditioned loop. My problem is, it seems like my broadcast is never received by any threads, as every thread that waits for the signal waits forever, while the thread that sent the signal continues.
I've dumbed my code down to make it as simple as possible while still being compileable and runnable:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#define num_threads 4
int repeat = 1;
int timesLooped = 0;
int waitingThreads = 0;
int threadNo = -1;
pthread_mutex_t mutex1;
pthread_cond_t condition;
//thread body
void* threadBody(void* arg){
//sensitive info: requires lock
if(pthread_mutex_lock(&mutex1)){ printf("error1\n"); }
threadNo++;
int threadId = threadNo;
//other info is set here as well in my code
if(pthread_mutex_unlock(&mutex1)){ printf("error2\n"); }
//main loop in the thread body
while(repeat == 1){
if(pthread_mutex_lock(&mutex1)){ printf("error3\n"); }
//wait until all threads are ready
while(waitingThreads < num_threads - 1){
printf(" %d! ", threadId);
waitingThreads++;
pthread_cond_wait(&condition, &mutex1);
printf(" %d ", threadId);
if(pthread_mutex_unlock(&mutex1)){ printf("error4\n"); }
}
//last thread will broadcast
if(waitingThreads == num_threads - 1){
printf("\n\nthread %d was last! broadcasting to let everyone proceed...", threadId);
timesLooped++;
waitingThreads = 0;
if(timesLooped == 3){
repeat = 0;
}
sleep(1);
pthread_cond_broadcast(&condition);
if(pthread_mutex_unlock(&mutex1)){ printf("error5\n"); }
}
}
printf("\n\nexiting thread %d\n", threadId);
pthread_exit((void*) arg);
}
int main(int argc, char** argv){
pthread_t threads[num_threads];
void* retval;
//create threads
for(long i = 0; i < num_threads; i++){
pthread_create(&threads[i], NULL, threadBody, (void*) i);
}
//join threads
for(long j = 0; j < num_threads; j++){
pthread_join(threads[j], &retval);
}
printf("\n\nDONE\n");
}
This gives me an output of:
thread 3 was last! broadcasting to let everyone proceed...
thread 2 was last! broadcasting to let everyone proceed...
thread 1 was last! broadcasting to let everyone proceed...
exiting thread 1 (deadlock, other threads never exit)
There are at least two bugs in your program.
You have a data race (see this blog post).
When threads 0 through num_threads - 1 access waitingThreads in if (waitingThreads == num_threads - 1) ..., they do so outside of the lock (i.e. they race).
You don't allow threads other than the last one to run (this is your primary question).
pthread_cond_wait returns when both condition has been signaled and the mutex can be re-acquired.
But your last thread immediately re-acquires the mutex upon releasing it, so no other thread can proceed.
I expect that if you add sleep or usleep after pthread_mutex_unlock in the last thread, your program will start working as you expect it to.
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;
}
I wanted to make a program that writes the odd and even numbers between 1 and 100 with 2 functions , the first function prints the first 5 odd numbers , the second function prints the first 5 even numbers and again we return to the first function to print the second 5 odd numbers and so on .
In this program i wanted to alternate between only 2 threads , but i can't find the solution . Here's my code , in this code i created 40 threads.Does anyone knows how to alternate between 2 threads and find the same output.
#include<stdio.h>
#include<pthread.h>
pthread_t tid[40];
int pair=2;
int impair=1 ;
pthread_mutex_t lock;
void* genpair(void *arg)
{
pthread_mutex_lock(&lock);
int i = 0;
for (i=0 ; i<5 ; i++,pair+=2)
{
printf("%d ",pair) ;
}
printf(" ");
pthread_mutex_unlock(&lock);
return NULL;
}
void* genimpair(void *arg)
{
pthread_mutex_lock(&lock);
int i = 0;
for (i=0 ; i<5 ; i++,impair+=2)
{
printf("%d ",impair) ;
}
printf(" ");
pthread_mutex_unlock(&lock);
return NULL;
}
int main(void)
{
int i = 0;
int j=0 ;
int err;
if (pthread_mutex_init(&lock, NULL) != 0)
{
printf("\n mutex init failed\n");
return 1;
}
for(j=0 ; j<20 ; j+=2)
{
pthread_create(&(tid[j]), NULL, &genpair, NULL);
pthread_create(&(tid[j+1]), NULL, &genimpair, NULL);
pthread_join(tid[j], NULL);
pthread_join(tid[j+1], NULL);
}
pthread_mutex_destroy(&lock);
return 0;
}
You cannot ensure which thread will be able to pass before the other with mutexes only. A mutex is there only to ensure that only one thread will be able to run the critical code. You can use a conditional variable associated to your mutex to make them pass one after the other, as in the following pseudo code:
// thread1
do {
lock(m);
while (turn==0) cond_wait(m); // release the key if not my turn, retry until my turn
do my job;
turn = 0; // give hand to the other
cond_broadcast(m); // awake threads waiting for key (blocked in lock or cond_wait)
unlock(m); // release the lock
} while ();
// thread2
do {
lock(m);
while (turn==1) cond_wait(m);
do my job;
turn = 1;
cond_broadcast(m);
unlock(m);
} while();
You can also use two semaphores for the same job...
You must use 2 different mutex and your code be like this
//Thread pair
{
pthread_mutex_lock(&pairLock)
//Do pair job
pthread_mutex_unlock(&impairLock)
}
//Threa impair
{
pthread_mutex_lock(&impairLock)
//Do impair job
pthread_mutex_unlock(&pairLock)
}
The mutex of the starting thread must start at 1 (unlocked) and the other one at 0 (locked)
Edit: Using the same mutex for all your threads makes that only one thread can do it's job but doesn't force any order or alternance (Depends on system scheduler). In your case genimpair could execute first if scheduler says so, but it won't be interrupted by genpair, in the next loop it could be same order or not