I have a worker thread doing a polling activity (it's targeting libcurl but that is not relevant).
Many actions from the application can start a worker thread but if it is already running, no new thread should be created. A new request from the application is simply joined with any other polling already ongoing.
In summary, a single worker thread that exits when there is nothing left to do.
The code is:
pthread_t thread = NULL;
struct timespec sleep_val = {0, 20000000};
void *worker_thread(void *threadid)
{
do {
poll();
nanosleep(&sleep_val, NULL);
} while (no_of_handles_running > 0);
pthread_exit(NULL);
thread = NULL;
}
void start_worker_thread_if_needed() {
if (thread == NULL) {
pthread_create(&thread, NULL, worker_thread, NULL);
}
}
My doubt is about thread safety. The function start_worker_thread_if_needed() can be called at any time any number of times.
So, what if start_worker_thread_if_needed() is called exactly when we exit the while loop and therefor interrupts the worker thread. If that happens the condition if (thread == NULL) will be FALSE since the worker thread is interrupted and pthread_exit + thread = NULL has not yet completed.
So now start_worker_thread_if_needed() will exit without creating a new thread but as soon as control is returned to the old worker thread it will continue to the pthread_exit line and the worker thread is destroyed.
The issue will be that the request that was just made triggering start_worker_thread_if_needed() will be lost and the polling will not start until the next call to start_worker_thread_if_needed().
Edit: Here is a suggestion with mutex but I still have the same doubt. What happens if the main thread interrupts just after we exit the while loop and before the worker can take the mutex. Then the main thread does not create a new thread and then the worker exit.
void *worker_thread(void *threadid)
{
do {
poll();
nanosleep(&sleep_val, NULL);
} while (no_of_handles_running > 0);
pthread_mutex_lock(&my_mutex);
thread = NULL;
pthread_mutex_unlock(&my_mutex);
pthread_exit(NULL);
}
void start_worker_thread_if_needed() {
pthread_mutex_lock(&my_mutex);
if (thread == NULL) {
pthread_create(&thread, NULL, worker_thread, NULL);
}
pthread_mutex_unlock(&my_mutex);
}
I think I have a flaw in how I have set this up and it would be highly appreciated if someone could help out with the proper solution.
Thanks to for all the help in the comments above. Kaylums suggestion to use condition variables seems to be a good approach to not risk ending up with the corner case I was concerned about.
The final code (with logs removed) is the one below and it appears to work just fine.
static int no_of_handles_running;
static int RUN_THREAD = 0;
pthread_t thread = NULL;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;;
void *worker_thread(void *threadid)
{
RUN_THREAD = 1;
do {
poll(); //Will update no_of_handles_running
if (no_of_handles_running == 0) {
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cv, &mutex);
pthread_mutex_unlock(&mutex);
}
} while (RUN_THREAD);
thread = NULL;
pthread_exit(NULL);
}
void start_worker_thread() {
if (thread == NULL) {
int rc = pthread_create(&thread, NULL, worker_thread, NULL);
if (rc){
return;
}
}
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mutex);
}
void stop_worker_thread() {
RUN_THREAD = 0;
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mutex);
}
Related
So reading this topic, the common way to exit would be using a flag. My question is, how is the waiting handled? Say the thread is only to run every 30s, how would you wait those 30s properly?
Using sem_timedwait() isn't ideal as it relies on the system clock and any change to the clock can severely impact your application. This topic explains using condition variables instead. The problem is, it relies on a mutex. You can't safely use pthread_mutex_lock() and pthread_mutex_unlock() in a signal handler. So in terms of my example above of 30s, if you want to exit immediately, who is handling the mutex unlock?
My guess would be another thread that sole purpose is to check the exit flag and if true it would unlock the mutex. However, what is that thread like? Would it not be wasted resources to just sit there constantly checking a flag? Would you use sleep() and check every 1s for example?
I don't believe my guess is a good one. It seems very inefficient and I run into similar "how do I wait" type of question. I feel like I'm missing something, but my searching is leading to topics similar to what I linked where it talks about flags, but nothing on waiting.
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
pthread_mutex_t my_mutex;
volatile sig_atomic_t exitRequested = 0;
void signal_handler(int signum) {
exitRequested = 1;
}
bool my_timedwait(pthread_mutex_t *mutex, int seconds) {
pthread_condattr_t attr;
pthread_condattr_init(&attr);
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
pthread_cond_t cond;
pthread_cond_init(&cond, &attr);
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_sec += seconds;
int status = pthread_cond_timedwait(&cond, mutex, &ts);
if (status == 0) {
return false; // mutex unlocked
}
if ((status < 0) && (status != ETIMEDOUT)) {
// error, do something
return false;
}
return true; // timedout
}
void *exitThread(void *ptr) {
// constant check???
while (1) {
if (exitRequested) {
pthread_mutex_unlock(&my_mutex);
break;
}
}
}
void *myThread(void *ptr) {
while (1) {
// do work
printf("test\n");
// wait and check for exit (how?)
if (!my_timedwait(&my_mutex, 30)) {
// exiting
break;
}
}
}
int main(void) {
// init and setup signals
struct sigaction sa;
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, NULL);
// init the mutex and lock it
pthread_mutex_init(&my_mutex, NULL);
pthread_mutex_lock(&my_mutex);
// start exit thread
pthread_t exitHandler;
pthread_create(&exitHandler, NULL, exitThread, NULL);
// start thread
pthread_t threadHandler;
pthread_create(&threadHandler, NULL, myThread, NULL);
// wait for thread to exit
pthread_join(threadHandler, NULL);
pthread_join(exitHandler, NULL);
return EXIT_SUCCESS;
}
The solution is simple. Instead of having the first thread block in pthread_join, block that thread waiting for signals. That will ensure that a SIGINT can be handled synchronously.
You need a global structure protected by a mutex. It should count the number of outstanding threads and whether or not a shutdown is requested.
When a thread finishes, have it acquire the mutex, decrement the number of outstanding threads and, if it's zero, send a SIGINT. The main thread can loop waiting for a signal. If it's from the thread count going to zero, let the process terminate. If it's from an external signal, set the shutdown flag, broadcast the condition variable, unlock the mutex, and continue waiting for the thread count to hit zero.
Here's a start:
pthread_mutex_t my_mutex; // protects shared state
pthread_cond_t my_cond; // allows threads to wait some time
bool exitRequested = 0; // protected by mutex
int threadsRunning = 0; // protected by mutex
pthread_t main_thread; // set in main
bool my_timedwait(int seconds)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_sec += seconds;
pthread_mutex_lock (&my_mutex);
while (exitRequested == 0)
{
int status = pthread_cond_timedwait(&my_cond, &my_mutex, &ts);
if (status == ETIMEDOUT) // we waited as long as supposed to
break;
}
bool ret = ! exitRequested;
pthread_mutex_unlock (&my_mutex);
return ret; // timedout
}
bool shuttingDown()
{
pthread_mutex_lock (&my_mutex);
bool ret = exitRequested;
pthread_mutex_unlock (&my_mutex);
return ret;
}
void requestShutdown()
{
// call from the main thread if a SIGINT is received
pthread_mutex_lock (&my_mutex);
exitRequested = 1;
pthread_cond_broadcast (&my_cond);
pthread_mutex_unlock (&my_mutex);
}
void threadDone()
{
// call when a thread is done
pthread_mutex_lock (&my_mutex);
if (--threadsRunning == 0)
pthread_kill(main_thread, SIGINT); // make the main thread end
pthread_mutex_unlock (&my_mutex);
}
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'm using c posix threads, and i've encountered a problem I don't quite understand and would like some fresh eyes to see what the problem could be.
In summary, I'm creating 3 threads which check some program state, signal that they are ready, and then wait for further signals. Meanwhile the thread that created these threads is waiting (pthread_cond_wait_) for each thread to signal that it has been setup. However it seems that the mutex is never unlocked once a wait has been signaled, causing the program the halt entirely.
This is the code for the main thread:
pthread_mutex_lock(&scenario->mutex);
if (scenario->flags.sinkThreadSetup == 0) {
pthread_create(&sinkT, NULL, sinkProblemHandler, (void *)scenario);
pthread_cond_wait(&scenario->sinkSetupCondition, &scenario->mutex);
}
if (scenario->flags.freeThreadSetup == 0) {
pthread_create(&freeT, NULL, freeWheelProblemHandler, (void *)scenario);
pthread_cond_wait(&scenario->freeSetupCondition, &scenario->mutex);
}
if (scenario->flags.blockThreadSetup == 0) {
pthread_create(&blockT, NULL, blockProblemHandler, (void *)scenario);
pthread_cond_wait(&scenario->blockSetupCondition, &scenario->mutex);
}
scenario->state = VECTORING;
pthread_mutex_unlock(&scenario->mutex);
// Start wheel threads
pthread_t wheelThreads[NUM_WHEELS];
scenario_wheel_t threadDataArr[NUM_WHEELS];
for (int i =0; i < NUM_WHEELS; i++) {
threadDataArr[i].scenario = scenario;
threadDataArr[i].wheel = &scenario->wheels[i];
pthread_create(&wheelThreads[i], NULL, wheel_start, (void *)&threadDataArr[i]);
}
pthread_mutex_lock(&scenario->mutex);
pthread_cond_wait(&scenario->scenarioComplete_condition, &scenario->mutex);
pthread_mutex_unlock(&scenario->mutex);
Here is the code for the problem handler threads:
void *sinkProblemHandler(void *args) {
scenario_t *scenario = (scenario_t *) args;
while(scenario->flags.terminate != 1) {
pthread_mutex_lock(&scenario->mutex);
if (scenario->state == SETUP && scenario->flags.sinkThreadSetup == 0) {
scenario->flags.sinkThreadSetup = 1;
pthread_cond_signal(&scenario->sinkSetupCondition);
}
if (scenario->state != SINKING) {
pthread_cond_wait(&scenario->conditions.sinking_condition, &scenario->mutex);
if (scenario->flags.terminate == 1) {
pthread_mutex_unlock(&scenario->mutex);
pthread_exit(NULL);
}
printf("SINKHandler: I'M HELPING!");
}
pthread_mutex_unlock(&scenario->mutex);
}
pthread_exit(NULL);
}
void *blockProblemHandler(void *args) {
scenario_t *scenario = (scenario_t *) args;
while(scenario->flags.terminate != 1) {
pthread_mutex_lock(&scenario->mutex);
if (scenario->state == SETUP && scenario->flags.blockThreadSetup == 0) {
scenario->flags.blockThreadSetup = 1;
pthread_cond_signal(&scenario->blockSetupCondition);
}
if (scenario->state != BLOCKED) {
pthread_cond_wait(&scenario->conditions.blocked_condition, &scenario->mutex);
if (scenario->flags.terminate == 1) {
pthread_mutex_unlock(&scenario->mutex);
pthread_exit(NULL);
}
printf("BlockHandler: I'M HELPING!");
}
pthread_mutex_unlock(&scenario->mutex);
}
pthread_exit(NULL);
}
void *freeWheelProblemHandler(void * args) {
scenario_t *scenario = (scenario_t *) args;
while(scenario->flags.terminate != 1) {
pthread_mutex_lock(&scenario->mutex);
if (scenario->state == SETUP && scenario->flags.freeThreadSetup == 0) {
scenario->flags.freeThreadSetup = 1;
pthread_cond_signal(&scenario->freeSetupCondition);
}
if (scenario->state != BLOCKED) {
pthread_cond_wait(&scenario->conditions.freeWheeling_condition, &scenario->mutex);
if (scenario->flags.terminate == 1) {
pthread_mutex_unlock(&scenario->mutex);
pthread_exit(NULL);
}
printf("FreeHandler: I'M HELPING!");
}
pthread_mutex_unlock(&scenario->mutex);
}
pthread_exit(NULL);
}
We can see here that the problem handler threads signal their respective setup condition, and then wait for a different condition (pthread_cond_wait),which should unlock the mutex.
My initial thought was that the problem handler threads were signaling before the main thread has started waiting, thus creating a deadlock. However after attaching to the program, this is not the case, as the program does:
1. Starts a problem thread
2. waits for the problem setup condition (unlocking mutex)
3. problem handler thread lock mutex.
3. problem handler thread then signals setup complete
4. problem handler thread then waits (supposedly unlocking mutex)
5. Program halts completely. (like the mutex has not been unlocked).
Any help would be greatly appreciated.
Thanks
Your worker threads roughly all have the form of
while(var) {
pthread_mutex_lock(&scenario->mutex);
// ...
pthread_mutex_unlock(&scenario->mutex);
}
that is mutex is locked immediately after it is unlocked. The main thread has a little chance to continue execution, as it cannot reacquire the mutex.
This is from man pthread_cond_signal:
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, at a bare minimum you can try pthread_yield() before reacquiring the mutex in the worker threads; and even better reduce the usage of mutex and / or introduce different mutexes to let different sections run in parallel.
I need a thread that will call continuously in while(1), but when i use to call thread function by pthread_create() a new thread creates.
I need help on following points :~
1) Is there any method to call thread function without creating thread.
2) Is there any method to destroy the previous thread.
Sample code is
void main()
{
pthread_t thread1;
while(1)
{
pthread_create( &thread1, NULL, myFun, (void*) NULL);
}
}
void * myFun(void *ptr)
{
printf("Hello");
}
* We can not create more than 380 threads, Here we have to use only single thread.
um, I think what you really want to do is like that:
bool received_data = false;
bool beExit = false;
struct recvPacket;
pthread_mutex_t recvMutex;
void main()
{
pthread_t thread1;
void *status;
pthread_mutex_init(&recvMutex, NULL);
pthread_create(&thread1, NULL, myFun, (void*) NULL);
while(1)
{
if (received_data) {
pthread_mutex_lock(&recvMutex); // you should also synchronize received_data and beExit valuables, cuz they are shared by two threads
/* do what you want with recvPacket */
pthread_mutex_unlock(&recvMutex);
received_data == false;
}
/* do else you want, or you can let beExit = true to stop the thread */
}
if (err = pthread_join(thr_main, &status))
printf("pthread_join Error. %s\n", strerror(err)), exit(1);
}
void * myFun(void *ptr)
{
while (!beExit) {
if (true == tryRecvPacket()) {
pthread_mutex_lock(&recvMutex);
/* fill data to recvPacket */
pthread_mutex_unlock(&recvMutex);
received_data = true;
}
}
}
Suggested design is.
void * myFun(void *ptr);
volatile int thread_exit = 1;
void main()
{
pthread_t thread1;
pthread_create( &thread1, NULL, myFun, (void*) NULL);
while(1)
{
//Ask every 10 sec for killing thread like
sleep(10);
printf("Do you wish to kill [0/1]???");
scanf("%d", &thread_exit);
}
//Add code here to make main() to wait till thread dies.
//pthread_join(&thread1);
}
void * myFun(void *ptr)
{
while(thread_exit)
{
printf("Hello");
}
}
For destroying the thread, you can use pthread_kill function available
int pthread_kill(pthread_t thread, int sig);
But its not good practice to kill the thread forcefully as it might cause the problem of the memory leak.
When the parent thread is finished, then all the child threads are finished abruptly.
In your example, as child thread will be in the infinite loop so child thread never finishes. But parent thread-main thread will finish after executing the return 0 statement. So main thread will terminate the child thread also.
To overcome this situation i.e. wait until all child threads have finished, pthread_join(thread1) method is there. So the thread calling this function will wait unless thread1 has finished.
Thanks to all for quick reply..
Problem has been fixed by using following code.
setsockopt (socket_desc, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
Here i set the timeout for accept the tcp clients request in microseconds.. now code is working OK.
I have 4 threads to create thread1, thread2, thread3 and thread4:
pthread_create(thread1,NULL,thread_func1,NULL);
pthread_create(thread2,NULL,thread_func2,NULL);
pthread_create(thread3,NULL,thread_func3,NULL);
pthread_create(thread4,NULL,thread_func4,NULL);
looking in the debug , The order of launched threads is not the same as defined in the source code.
Are there a solution to launch the threads with an order that I could define?
The launch order is sequential, in that the create calls happen in the order they're written.
However the scheduler for whatever reason isn't scheduling the newly launched threads in the order you hoped. If the order matters perhaps threads isn't what you want? The big advantage with threads is that they don't always get scheduled in a sequential order!
If you really want though you can use synchronisation primitives (e.g. a series of mutexes, or a condvar) to ensure that up to a certain point happens in predictable order, but from that point onwards the order will still be down to the whims of the scheduler. As an example this code guarantees that each thread will print its ID in the order they were created:
#include <pthread.h>
#include <stdio.h>
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void sync_threads(const int num, int *cur) {
pthread_mutex_lock(&mut);
while (*cur != num) {
pthread_cond_wait(&cond, &mut);
}
// Do work that must happen in order here:
printf("Thread: %d\n", num);
++*cur;
pthread_mutex_unlock(&mut);
pthread_cond_broadcast(&cond);
}
static int num = 1;
void *thread1(void *d) {
sync_threads(1,&num);
while (1); // Rest of work happens whenever
return NULL;
}
void *thread2(void *d) {
sync_threads(2,&num);
while (1);
return NULL;
}
void *thread3(void *d) {
sync_threads(3,&num);
while (1);
return NULL;
}
void *thread4(void *d) {
sync_threads(4,&num);
while (1);
return NULL;
}
int main() {
pthread_t t1,t2,t3,t4;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_create(&t3, NULL, thread3, NULL);
pthread_create(&t4, NULL, thread4, NULL);
while(1) {
// some work
}
}
I've used while(1); to simulate some real work happening. It does this with a mutex protecting the "current" thread, i.e. the order of initialisation and then a condvar to make sleeping/waking possible. It broadcasts to all threads who then check to see which one is up next. You could design as system that skips the broadcast, but that complicates things for relatively little gain.
You can also add more synchronisation if required at other points, but the more you synchronise things the less point there is in having threads in the first place.
Ideally if things need to happen in a predictable order they should be done before spawning threads, not as soon as the threads spawn, e.g.:
fixed_init_for_thread1();
fixed_init_for_thread2();
fixed_init_for_thread3();
fixed_init_for_thread4();
pthread_create(thread1,NULL,thread_func1,NULL);
pthread_create(thread2,NULL,thread_func2,NULL);
pthread_create(thread3,NULL,thread_func3,NULL);
pthread_create(thread4,NULL,thread_func4,NULL);
such that by the time the threads are created you don't care which one actually gets given the chance to run first.
I don't think you really care which thread executed first. If you just need an unique identifier for the four threads, check pthread_self. To have sequential IDs, call the ID allocator from within the thread; or generate the ID and pass it as user parameter when calling pthread_create.
here after the solution I used
#include <pthread.h>
#include <stdio.h>
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static bool wait = TRUE;
void thread_sync() {
pthread_mutex_lock(&mut);
wait = FALSE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mut);
}
void thread_wait_sync() {
pthread_mutex_lock(&mut);
if (wait==TRUE)
{
pthread_cond_wait(&cond,&mut);
}
wait = TRUE;
pthread_mutex_unlock(&mut);
}
void *thread1(void *d) {
thread_sync();
while (1); // Rest of work happens whenever
return NULL;
}
void *thread2(void *d) {
thread_sync();
while (1);
return NULL;
}
void *thread3(void *d) {
thread_sync();
while (1);
return NULL;
}
void *thread4(void *d) {
while (1);
return NULL;
}
int main() {
pthread_t t1,t2,t3,t4;
pthread_create(&t1, NULL, thread1, NULL);
thread_wait_sync();
pthread_create(&t2, NULL, thread2, NULL);
thread_wait_sync();
pthread_create(&t3, NULL, thread3, NULL);
thread_wait_sync();
pthread_create(&t4, NULL, thread4, NULL);
while(1) {
// some work
}
}
Move 'pthread_create(thread2,NULL,thread_func2,NULL);' into thread_func1()
Move 'pthread_create(thread3,NULL,thread_func2,NULL);' into thread_func2()
Move 'pthread_create(thread4,NULL,thread_func2,NULL);' into thread_func3()
This is VERY close to the other question posted recently and just as err.. 'strange'