I want to finish my threads with a mutex. The first thread won't execute, thread 2 & 3 execute.
Does anyone know what this problem could be? Sometimes thread 1 is executed but then 2 or 3 is not executed. I don't know what the problem is here.
Thread created successfully
Thread created successfully
Thread created successfully
----------------------------------------------------
J:0
NUM_REQUESTS (before function): 0
J:0
----------------------------------------------------
----------------------------------------------------
J:1
Third thread processing done
WRITE DATA TO LIST!
NUM_REQUESTS(function): 1
NUM_REQUESTS (before function): 0
J:1
----------------------------------------------------
----------------------------------------------------
J:2
Second thread processing done
WRITE DATA TO LIST!
NUM_REQUESTS(function): 0
NUM_REQUESTS (before function): 0
J:2
----------------------------------------------------
Program:
#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
pthread_mutex_t request_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t got_request = PTHREAD_COND_INITIALIZER;
pthread_t tid[3];
int thr_id[3];
int ret1,ret2,ret3;
int i = 0;
int err;
int *ptr[2];
int num_requests = 0;
int rc = 0;
This is the function of the threads, the first thread is not executed!
void* doSomeThing(void *arg)
{
unsigned long i = 0;
pthread_t id = pthread_self();
for(i=0; i<1000000;i++);
if(pthread_equal(id,tid[0]))
{
printf("First thread processing done\n");
printf("WRITE DATA TO LIST!\n");
num_requests--;
printf("NUM_REQUESTS(function): %d\n",num_requests);
rc = pthread_mutex_unlock(&request_mutex);
pthread_exit(&tid[0]);
}else if(pthread_equal(id,tid[1])){
printf("Second thread processing done\n");
num_requests--;
printf("WRITE DATA TO LIST!\n");
printf("NUM_REQUESTS(function): %d\n",num_requests);
rc = pthread_mutex_unlock(&request_mutex);
pthread_exit(&tid[1]);
}else if(pthread_equal(id,tid[2])){
printf("Third thread processing done\n");
printf("WRITE DATA TO LIST!\n");
printf("NUM_REQUESTS(function): %d\n",num_requests);
num_requests--;
rc = pthread_mutex_unlock(&request_mutex);
pthread_exit(&tid[2]);
}
return NULL;
}
This is where i create the output of the threads
void add_request(int j,pthread_mutex_t* p_mutex,pthread_cond_t* p_cond_var)
{
printf("----------------------------------------------------\n");
printf("J:%d\n",j);
if(num_requests > 3){
printf("WAIT TILL THREADS ARE FREE!\n");
}else{
rc = pthread_mutex_lock(&request_mutex);
printf("NUM_REQUESTS (before function): %d\n",num_requests);
num_requests++;
rc = pthread_mutex_unlock(&request_mutex);
rc = pthread_mutex_lock(&request_mutex);
rc = pthread_cond_signal(p_cond_var);
printf("J:%d\n",j);
printf("----------------------------------------------------\n");
}
}
In the main i only create the threads and use the add_request function to execute the threads
int main(void)
{
//create 3 threads
while(i < 3)
{
thr_id[i] = i;
err = pthread_create(&(tid[i]), NULL, &doSomeThing, (void*)&thr_id[i]);
if (err != 0)
printf("can't create thread :[%s]", strerror(err));
else
printf("Thread created successfully\n");
i++;
}
int j;
for(j=0;j<3;j++){
add_request(j, &request_mutex, &got_request);
}
return 0;
}
what are you trying to do?
At least one problem I see it that you unlock the mutex without locking it...
When you create a thread it starts spontaneously (more or less) so you can't assume add_request will be called after doSomething().
You can lock and then unlock. Also consider using ptheard_join if you want to wait until the threads finish.
EDIT
this is what you want to do https://computing.llnl.gov/tutorials/pthreads/samples/condvar.c
-taken from https://computing.llnl.gov/tutorials/pthreads/
Good luck
Related
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.
The requirement for the sample application creating using pthread is given below:
A single thread is created from main using Pthread
Inside thread, Mutex is locked, a counter counts the value and while loop is incremented, While is set to the max count of 10.
after while loop finishes, the mutex is unlocked.
The above requirement I have tried implementing using pthread
Code is shown below:
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;
int samples = 10;
int count = 0;
struct example
{
int i;
int a;
};
void *inc_x(void *x_void_ptr)
{
pthread_mutex_lock(&count_mutex);
printf("Thread is locked \n");
while(count < samples)
{
printf("inside While loop \n");
struct example *E2_ptr;
E2_ptr = (struct example *)x_void_ptr;
printf("inside thread count = %d\n",count);
E2_ptr->a = count;
E2_ptr->i = (count + 1);
count ++;
//pthread_cond_wait(&count_threshold_cv, &count_mutex);
}
pthread_mutex_unlock(&count_mutex);
printf ( "\n Test Successful for Thread\n");
pthread_exit(NULL);
}
int main()
{
int x = 100, y = 0,i = 0;
struct example *E1_ptr;
E1_ptr->a = 0;
E1_ptr->i = 0;
printf("Before\t E1_ptr->a = %d\t, E1_ptr->i = %d\n",E1_ptr->a,E1_ptr->i);
pthread_t inc_x_thread;
if(pthread_create(&inc_x_thread, NULL, inc_x, E1_ptr))
{
printf("Error creating thread\n");
}
if(pthread_join(inc_x_thread, NULL))
{
printf("Error joining thread\n");
}
for(i = 0; i<(samples-1); i++)
{
if(pthread_cond_signal(&count_threshold_cv))
{
printf("Error Signaling thread at sample = %d\n",i);
}
}
printf("after\t E1_ptr->a = %d\t, E1_ptr->i = %d\n",E1_ptr->a,E1_ptr->i);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
pthread_exit (NULL);
return 0;
}
Doubt:
In the above code, the thread executes its function properly and exits.
Once the condition is applied, i.e. the below shown code is uncommented then,
pthread_cond_wait(&count_threshold_cv, &count_mutex);
Then the thread is stopped after 1st iteration of while loop as expected.
The signal is generated from main by the code shown below:
for(i = 0; i<(samples-1); i++)
{
if(pthread_cond_signal(&count_threshold_cv))
{
printf("Error Signaling thread at sample = %d\n",i);
}
}
observed that the signal is never sent.
Can someone please guide me, where am I going wrong. I'm a newbie to Pthreads.
Thanks in advance.
count_mutex and count_threshold_cv are not initialized, add:
int main()
{
pthread_mutex_init(&count_mutex, NULL);
pthread_cond_init(&count_threshold_cv, NULL);
//...
E1_ptr is not initialized.
There are many ways to solve it:
You can call malloc to allocate memory:
struct example *E1_ptr = malloc(sizeof(struct example));
E1_ptr->a = 0;
E1_ptr->i = 0;
or holds pointer to local variable:
struct example ex;
struct example *E1_ptr = &ex; //malloc(sizeof(struct example));
E1_ptr->a = 0;
E1_ptr->i = 0;
or
struct example ex;
ex.a = 0;
ex.i = 0;
then create thread with pthread_create(&inc_x_thread, NULL, inc_x, &ex)
pthread_cond_signal function does not wait. If a thread is blocked by condition variable pthread_cond_signal function unblocks this thread, otherwise returns immediately without waiting and does nothing. So your for loop with 10 iterations is executed as soon as possible, without any waiting for pthread_cond_wait is called.
So can rewrite your for loop to infinite loop, calling pthread_cond_signal repeatedly.
if(pthread_create(&inc_x_thread, NULL, inc_x, E1_ptr)) {
printf("Error creating thread\n");
}
while(1) { // INFINITE LOOP
if(pthread_cond_signal(&count_threshold_cv)) {
printf("Error Signaling thread at sample = %d\n",i);
}
if (taskDone) // testing global flag, if 1 break
break; // it means inc_x thread has ended
}
if(pthread_join(inc_x_thread, NULL)) { // it was pointed out in comment
printf("Error joining thread\n"); // you need to join at the end of main function
}
taskDone is global int, with 0 as default value. It is set to 1 before pthread_exit is called in inc_x function. Setting/checking taskDone should be wrapped with some synchronization mechanism, for example by adding new mutex or use count_mutex.
I have a multiple read threads and one write thread. If I lock mutex on one of the read threads and send broadcast from it, is it guaranteed that mutex will be locked by write thread waiting on pthread_cond_wait() or is there a possibility that another read thread that is wainting on pthread_mutex_lock() will lock mutex? Main question is does pthread_cond_wait() have priority over pthread_mutex_lock()?
If not, how can I achieve that the mutex will always be locked by write thread on pthread_cond_broadcast()?
Example
Read thread:
pthread_mutex_lock(mutex);
pthread_cond_broadcast(cond);
pthread_mutex_unlock(mutex);
Write thread:
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
Let's assume both threads, read and write, reach the pthread_mutex_lock in the same moment. So, either write thread acquire the mutex on pthread_mutex_lock call, or read thread.
If it would be the write thread, the read one will wait on pthread_mutex_lock. The write, by calling pthread_cond_wait releases mutex and blocks on cond. It is done atomically. So, when read thread is grantex the mutex, we can be sure the the read one waits on cond. So, broadcast on cond reaches the write thread, it no more waits on cond but - still in scope of pthread_cond_wait - tries to get a lock on mutex (hold be read thread). After broadcasting cond the read thread releases the mutex and it goes to write thread. So write thread finally exits from pthread_cond_wait having the mutex locked. Remember to unlock it later.
If it would be the read thread, the write one will wait on pthread_mutex_lock, the read will broadcast a signal on cond then release the mutex. After then the write thread acquires the mutex on pthread_mutex_lock and immediately releases in it pthread_cond_wait waiting for cond (please note, that previous cond broadcast has no effect on current pthread_cond_wait). In the next iteration of read thread it acquires lock onmutex, send broadcast on cond and unlock mutex. It means the write thread moves forward on cond and acquires lock on mutex.
Does it answer your question about priority?
Update after comment.
Let's assume we have one thread (let's name it A for future reference) holding the lock on mutex and few other trying to acquire the same lock. As soon as the lock is released by first thread, there is no predictable which thread would acquire lock. Moreover, if the A thread has a loop and tries to reacquire lock on mutex, there is a chance it would be granted this lock and other threads would keep waiting. Adding pthread_cond_wait doesn't change anything in scope of granting a lock.
Let me quote fragments of POSIX specification (see https://stackoverflow.com/a/9625267/2989411 for reference):
These functions atomically release mutex and cause the calling thread to block on the condition variable cond; atomically here means "atomically with respect to access by another thread to the mutex and then the condition variable". That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_broadcast() or pthread_cond_signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.
And this is only guarantee given by standard regarding order of operations. Order of granting the lock to other threads is rather unpredictable and it changes depending on some very subtle fluctuation in timing.
For only mutex related code, please play a little with following code:
#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *th(void *arg) {
int i;
char *s = arg;
for (i = 0; i < 10; ++i) {
pthread_mutex_lock(&mutex);
printf("%s %d\n", s, i);
//sleep(1);
pthread_mutex_unlock(&mutex);
#if 0
pthread_yield();
#endif
}
return NULL;
}
int main() {
int i;
for (i = 0; i < 10; ++i) {
pthread_t t1, t2, t3;
printf("================================\n");
pthread_create(&t1, NULL, th, "t1");
pthread_create(&t2, NULL, th, " t2");
pthread_create(&t3, NULL, th, " t3");
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
}
return 0;
}
On one machine (single CPU) it always shows whole loop from t3, then t2 and finally from t1. On another (2 cores) the order of threads is more random, but almost always it shows whole loop for each thread before granting the mutex to other thread. Rarely there is a situation like:
t1 8
t1 9
t3 0
t2 0
t2 1
[removed other t2 output]
t2 8
t2 9
t3 1
t3 2
Enable pthread_yield by replacing #if 0 with #if 1 and watch results and check output. For me it works in a way two threads display their output interlaced, then third thread finally has a chance to work. Add another or more thread. Play with sleep, etc. It confirms the random behaviour.
If you wish to experiment a little, compile and run following piece of code. It's an example of single producer - multiple consumers model. It can be run with two parameters: first is the number of consumer threads, second is the length of produced data series. If no parameters are given there is one consumer thread and 120 items to be processed. I also recommend with sleep/usleep in places marked /* play here */: change the value of arguments, remove the sleep at all, move it - when appropriate - to critical section or replace with pthread_yield and observe changes in behaviour.
#define _GNU_SOURCE
#include <assert.h>
#include <limits.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
struct data_t {
int seq;
int payload;
struct data_t *next;
};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
struct data_t *first = NULL, *last = NULL;
int in_progress = 1;
int num_data = 120;
void push(int seq, int payload) {
struct data_t *e;
e = malloc(sizeof(struct data_t));
e->seq = seq;
e->payload = payload;
e->next = NULL;
if (last == NULL) {
assert(first == NULL);
first = last = e;
} else {
last->next = e;
last = e;
}
}
struct data_t pop() {
struct data_t res = {0};
if (first == NULL) {
res.seq = -1;
} else {
res.seq = first->seq;
res.payload = first->payload;
first = first->next;
if (first == NULL) {
last = NULL;
}
}
return res;
}
void *producer(void *arg __attribute__((unused))) {
int i;
printf("producer created\n");
for (i = 0; i < num_data; ++i) {
int val;
sleep(1); /* play here */
pthread_mutex_lock(&mutex);
val = rand() / (INT_MAX / 1000);
push(i, val);
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
printf("prod %3d %3d signaled\n", i, val);
}
in_progress = 0;
printf("prod end\n");
pthread_cond_broadcast(&cond);
printf("prod end signaled\n");
return NULL;
}
void *consumer(void *arg) {
char c_id[1024];
int t_id = *(int *)arg;
sprintf(c_id, "%*s c %02d", t_id % 10, "", t_id);
printf("%s created\n", c_id);
while (1) {
struct data_t item;
pthread_mutex_lock(&mutex);
item = pop();
while (item.seq == -1 && in_progress) {
printf("%s waits for data\n", c_id);
pthread_cond_wait(&cond, &mutex);
printf("%s got signal\n", c_id);
item = pop();
}
if (!in_progress && item.seq == -1) {
printf("%s detected end of data.\n", c_id);
pthread_mutex_unlock(&mutex);
break;
}
pthread_mutex_unlock(&mutex);
printf("%s processing %3d %3d\n", c_id, item.seq, item.payload);
sleep(item.payload % 10); /* play here */
printf("%s processed %3d %3d\n", c_id, item.seq, item.payload);
}
printf("%s end\n", c_id);
return NULL;
}
int main(int argc, char *argv[]) {
int num_cons = 1;
pthread_t t_prod;
pthread_t *t_cons;
int i;
int *nums;
if (argc > 1) {
num_cons = atoi(argv[1]);
if (num_cons == 0) {
num_cons = 1;
}
if (num_cons > 99) {
num_cons = 99;
}
}
if (argc > 2) {
num_data = atoi(argv[2]);
if (num_data < 10) {
num_data = 10;
}
if (num_data > 600) {
num_data = 600;
}
}
printf("Spawning %d consumer%s for %d items.\n", num_cons, num_cons == 1 ? "" : "s", num_data);
t_cons = malloc(sizeof(pthread_t) * num_cons);
nums = malloc(sizeof(int) * num_cons);
if (!t_cons || !nums) {
printf("Out of memory!\n");
exit(1);
}
srand(time(NULL));
pthread_create(&t_prod, NULL, producer, NULL);
for (i = 0; i < num_cons; ++i) {
nums[i] = i + 1;
usleep(100000); /* play here */
pthread_create(t_cons + i, NULL, consumer, nums + i);
}
pthread_join(t_prod, NULL);
for (i = 0; i < num_cons; ++i) {
pthread_join(t_cons[i], NULL);
}
free(nums);
free(t_cons);
return 0;
}
I hope I have cleared your doubts and gave you some code to experiment and gain some confidence about pthread behaviour.
I'm currently working on custom thread scheduler project that uses pthreads in C. I have been struggling conceptually with it but am finally getting the behavior I expect to see, save for the segmentation fault.
My job is to register five child threads and schedule each one based on the order of their IDs stored in an array. What I do is call pthread_mutex_lock and tell whichever child thread that is not to be scheduled first to wait. I do some stuff to my counter to keep track of when the next child should be scheduled and after one child thread increments counter to five it should wake up other threads and do the same thing for as many times as main loop is defined.
all variables:
#define NTHREADS 5 /* Number of child threads */
#define NUM_LOOPS 10 /* Number of local loops */
#define SCHEDULE_INTERVAL 1 /* thread scheduling interval */
#define errexit(code,str) fprintf(stderr,"%s: %s\n",(str),strerror(code));exit(1);
int schedule_vector[NTHREADS]; /* The thread schedule vector */
int flag = 0;
pthread_cond_t cv; // condtitional variable
pthread_mutex_t mtx; // mutex semaphore 1
int globalcounter = 0;
int currentThread;
#define TASK_LIMIT 6
here is parent thread:
int main(int argc,char *argv[])
{
int i;
int worker;
int ids[NTHREADS];
int errcode;
int *status;
int policy;
pthread_t threads[NTHREADS];
/* Create child threads --------------------------------------------- */
for (worker = 0; worker < NTHREADS; worker++)
{
ids[worker] = worker;
printf("creating child thread using id %d\n", worker);
/* Create a child thread ----------------------------------------- */
pthread_create (
&threads[worker],
NULL,
my_thread,
&ids[worker]);
}
/* Initialize the thread schedule vector -------------------------- */
schedule_vector[0] = 0; /* First thread to be executed (0) */
schedule_vector[1] = 1; /* Second thread to be exceuted (1) */
schedule_vector[2] = 2; /* Third thread to be executed (2) */
schedule_vector[3] = 3; /* Fourth thread to be executed (3) */
schedule_vector[4] = 4; /* Fifth thread to be executed (4) */
signal(SIGALRM, clock_interrupt_handler);
alarm(SCHEDULE_INTERVAL);
printf("handler set up\n");
/* Reap the threads as they exit ----------------------------------- */
for (worker = 0; worker < NTHREADS; worker++)
{
/* Wait for thread to terminate --- */
if (errcode=pthread_join(threads[worker],(void *) &status))
{ errexit(errcode,"pthread_join"); }
/* Check thread's exit status and release its resources -------- */
if (*status != worker)
{
fprintf(stderr,"thread %d terminated abnormally\n",worker);
exit(1);
}
}
/* The main (parent) thread terminates itself ---------------------- */
return(0);
}
Here is the child thread function:
void *my_thread(void * arg)
{
long int i;
long int counter;
int myid=*(int *) arg;
counter = 0;
printf("\nI am thread #%d\n\n", myid);
/* Main loop ------------------------------------------ */
for (i = 0; i < NUM_LOOPS; i++)
{
currentThread = myid;
pthread_mutex_lock(&mtx);
while(myid != schedule_vector[flag]){
pthread_cond_wait(&cv, &mtx);
}
counter++;
globalcounter = counter;
printf("Thread: %d is running ...\n", myid);
usleep(100000);
}
return arg;
}
and here is my interrupt handler:
void clock_interrupt_handler(void)
{
printf("scheduler started ++++++++++++++++++++++++++++++++++ \n");
if (currentThread == schedule_vector[flag]) {
printf("scheduled thread received: thread %d, and it's counter is at %d\n", currentThread, globalcounter);
while(globalcounter < TASK_LIMIT){
if(globalcounter == 5){
flag++;
pthread_cond_broadcast(&cv);
}
pthread_mutex_unlock(&mtx);
alarm(SCHEDULE_INTERVAL);
}
} else {
printf("unscheduled thread received, putting thread %d with count %d to sleep...\n", currentThread, globalcounter);
alarm(SCHEDULE_INTERVAL);
}
}
This is the output:
scheduler started ++++++++++++++++++++++++++++++++++
scheduled thread received: thread 0, and it's counter is at 1
Thread: 0 is running ...
Thread: 0 is running ...
Thread: 0 is running ...
Thread: 0 is running ...
Segmentation fault (core dumped)
It basically repeats this behavior, but for each thread. I'd like to understand what is exactly causing the seg fault
Seems pthread_mutex_lock/pthread_mutex_unlock do not pair.
The correct code looks like
pthread_mutex_lock()
pthread_cond_broadcast()
pthread_mutex_unlock()
pthread_mutex_lock()
pthread_cond_wait()
pthread_mutex_unlock()
I'm trying to write safe SIGINT handling for my multithreaded application and I'm using sleep() function to simulate entering "unsafe" zone - a place where a thread shouldn't be cancelled. Here's my code:
Global variables:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
pthread_mutex_t *global_mutex;
pthread_mutex_t **thread_mutexes;
pthread_mutex_t *firm_mutex;
pthread_attr_t *attr;
Thread:
void *thread(void *data)
{
int local_tid = *(int *) data;
printf("Starting thread %d\n", local_tid);
for (;;) {
pthread_mutex_lock(thread_mutexes[local_tid]);
int scnds = rand() % 5 + 1;
printf("%d locked\nSleeping for: %d seconds\n", local_tid, scnds);
sleep(scnds);
printf("%d woken up!\n", local_tid);
pthread_mutex_unlock(thread_mutexes[local_tid]);
}
}
Thread creation:
int main()
{
int n;
scanf("%d", &n);
printf("Starting signal handler with %d threads...\n",n);
global_mutex = malloc(sizeof(pthread_mutex_t));
firm_mutex = malloc(sizeof(pthread_mutex_t));
thread_mutexes = malloc(n * sizeof(pthread_mutex_t *));
for (int i = 0; i < n; i++) {
thread_mutexes[i] = malloc(sizeof(pthread_mutex_t));
}
attr = malloc(sizeof(pthread_attr_t));
if (pthread_attr_init(attr) != 0 ) {
perror("attrinit\n");
exit(1);
}
if (pthread_attr_setdetachstate (attr,PTHREAD_CREATE_JOINABLE) != 0) {
perror("setdetach\n");
exit(1);
}
for (int i = 0; i < n; i++) {
pthread_t tid;
if (pthread_mutex_init (thread_mutexes[i], 0) != 0) {
perror("mutexinit\n");
exit(1);
}
int *tdata = malloc(sizeof(int));
*tdata = i;
if (pthread_create (&tid, attr, watek, tdata) != 0) {
perror("pthread_create");
exit(1);
}
if (pthread_join (tid, 0) != 0) {
perror("join\n");
exit(1);
}
}
return 0;
}
So you would think that after launching with 10 threads, first thread should go to sleep immedietely and in the meantime another should start execution. Unfortuntely, after launching the program with 10 threads I get an output like this:
Starting signal handler with 10 threads...
Starting thread 0
0 locked
sleeping for: 4 seconds
0 woken up!
0 locked
sleeping for: 2 seconds
0 woken up!
0 locked
sleeping for: 3 seconds
0 woken up!
0 locked
sleeping for: 1 seconds
0 woken up!
0 locked
sleeping for: 4 seconds
0 woken up!
0 locked
Basically thread 0 steals all the time! Why aren't other threads executed when 0 sleeps?
if (pthread_create (&tid, attr, watek, tdata) != 0) {
perror("pthread_create");
exit(1);
}
if (pthread_join (tid, 0) != 0) {
perror("join\n");
exit(1);
}
You're creating the first thread and then waiting to pthread_join with it before creating the next one. The next loop iteration, therefore, (creating the next thread) won't happen until the first thread terminates.
If you want all the threads to start right away, just create and start them in the first loop - deal with waiting for them to complete later.