I've the following source code (adapted from my original code):
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include "pthread.h"
#define MAX_ENTRY_COUNT 4
int entries = 0;
bool start = false;
bool send_active = false;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condNotEmpty = PTHREAD_COND_INITIALIZER;
pthread_cond_t condNotFull = PTHREAD_COND_INITIALIZER;
void send()
{
for (;;) {
if (!start)
continue;
start = false;
for(int i = 0; i < 11; ++i) {
send_active = true;
pthread_mutex_lock(&mutex);
while(entries == MAX_ENTRY_COUNT)
pthread_cond_wait(&condNotFull, &mutex);
entries++;
pthread_cond_broadcast(&condNotEmpty);
pthread_mutex_unlock(&mutex);
send_active = false;
}
}
}
void receive(){
for(int i = 0; i < 11; ++i){
pthread_mutex_lock(&mutex);
while(entries == 0)
pthread_cond_wait(&condNotEmpty, &mutex);
entries--;
pthread_cond_broadcast(&condNotFull);
pthread_mutex_unlock(&mutex);
}
if (send_active)
printf("x");
}
int _tmain(int argc, _TCHAR* argv[])
{
pthread_t s;
pthread_create(&s, NULL, (void *(*)(void*))send, NULL);
for (;;) {
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&condNotEmpty, NULL);
pthread_cond_init(&condNotFull, NULL);
start = true;
receive();
pthread_mutex_destroy(&mutex);
mutex = NULL;
pthread_cond_destroy(&condNotEmpty);
pthread_cond_destroy(&condNotFull);
condNotEmpty = NULL;
condNotFull = NULL;
printf(".");
}
return 0;
}
The problem is like follows: from time to time the last unlock in the send function is not finished before the receive method continues. In my original code the mutexes are located in an objects which are deleted after doing the job. If the send method has not finished with the last unlock then the mutexes are invalid and my program causes failures in unlock.
The behavior can be easily reproduced by running the program: each time the "x" is diplayed the receive method has nearly finished and the send method "hangs" in the unlock call.
I've compiled with VS2008 and VS2010 - both results are same.
pthread_mutex_unlock is not atomic, this would solve the problem. How can I solve this issue? Any comments are welcome...
Best regards
Michael
Your printf("x") is a textbook race condition example.
After pthread_mutex_unlock() OS is free to not schedule this thread for any amount of time: ticks, seconds or days. You can't assume that send_active will be "falsified" in time.
pthread_mutex_unlock() must by definition release the mutex before it returns. The instant the mutex is released, another thread that's contending for the mutex could be scheduled. Note that even if pthread_mutex_unlock() could arrange to not release the mutex until just after it returned (what I think you mean by it being atomic), there would still be an equivalent race condition to whatever you're seeing now (it's not clear to me what race you're seeing since a comment indicates that ou're not realy interested in the race condition of accessing send_active to control the printf() call).
In that case the other thread could be scheduled 'between-the-lines' of the pthread_mutex_unlock() and the following statement/expression in the function that called it - you'd have the same race condition.
Here's some speculation on what might be happening. A couple caveats on this analysis:
this is based on the assumption that you're using the Win32 pthreads package from http://sourceware.org/pthreads-win32/
this is based only on a pretty brief examination of the pthreads source on that site and the information in the question and comments here - I have not had an opportunity to actually try to run/debug any of the code.
When pthread_mutex_unlock() is called, it decrements a lock count, and if that lock count drops to zero, the Win32 SetEvent() API is called on an associated event object to let any threads waiting on the mutex to be unblocked. Pretty standard stuff.
Here's where the speculation comes in. Lets say that SetEvent() has been called to unblock thread(s) waiting on the mutex, and it signals the event associated with the handle it was given (as it should). However, before the SetEvent() function does anything else, another thread starts running and closes the event object handle that that particular SetEvent() was called with (by calling pthread_mutex_destroy()).
Now the SetEvent() call in progress has a handle value that's no longer valid. I can't think of a particular reason that SetEvent() would do anything with that handle after it's signaled the event, but maybe it does (I could also imagine someone making a reasonable argument that SetEvent() should be able to expect that the event object handle remain valid for the duration of the API call).
If this is what's happening to you (and that's a big if), I'm not sure if there's an easy fix. I think that the pthreads library would have to have changes made so that it duplicated the event handle before calling SetEvent() then close that duplicate when the SetEvent() call returned. That way the handle would remain valid even if the 'main' handle were closed by another thread. I'm guessing it would have to do this in a number of places. This could be implemented by replacing the affected Win32 API calls with calls to wrapper functions that perform the "duplicate handle/call API/close duplicate" sequence.
It might not be unreasonable for you to try to make this change for the SetEvent() call in pthread_mutex_unlock() and see if it solves (or at least improves) your particular problem. If so, you may want to contact the maintainer of the library to see if a more comprehensive fix might be arranged somehow (be prepared - you may be asked to do a significant part of the work).
Out of curiosity, in your debugging of the state of the thread that hangs in pthread_mutex_unlock()/SetEvent(), do you have any information on exactly whats happening? What SetEvent() is waiting for? (the cdb debugger that's in the Debugging Tools for Windows package might be able to give you more information about this than the Visual Studio debugger).
Also, note the following comment in the source for pthread_mutex_destroy() which seems related (but different) than your particular problem:
/*
* FIXME!!!
* The mutex isn't held by another thread but we could still
* be too late invalidating the mutex below since another thread
* may already have entered mutex_lock and the check for a valid
* *mutex != NULL.
*
* Note that this would be an unusual situation because it is not
* common that mutexes are destroyed while they are still in
* use by other threads.
*/
Michael, thank you for your investigation and comments!
The code I'm using is from http://sourceware.org/pthreads-win32/.
The situation described by you in the third and fourth paragraph is exactly what's happening.
I've checked some solutions and a simple one seems to work for me: I waiting till the send function (and SetEvent) has finished. All my tests with this solution were successful till now. I'm going to do a larger test over the weekend.
Related
For an assignment, I need to use sched_yield() to synchronize threads. I understand a mutex lock/conditional variables would be much more effective, but I am not allowed to use those.
The only functions we are allowed to use are sched_yield(), pthread_create(), and pthread_join(). We cannot use mutexes, locks, semaphores, or any type of shared variable.
I know sched_yield() is supposed to relinquish access to the thread so another thread can run. So it should move the thread it executes on to the back of the running queue.
The code below is supposed to print 'abc' in order and then the newline after all three threads have executed. I looped sched_yield() in functions b() and c() because it wasn't working as I expected, but I'm pretty sure all that is doing is delaying the printing because a function is running so many times, not because sched_yield() is working.
The server it needs to run on has 16 CPUs. I saw somewhere that sched_yield() may immediately assign the thread to a new CPU.
Essentially I'm unsure of how, using only sched_yield(), to synchronize these threads given everything I could find and troubleshoot with online.
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <sched.h>
void* a(void*);
void* b(void*);
void* c(void*);
int main( void ){
pthread_t a_id, b_id, c_id;
pthread_create(&a_id, NULL, a, NULL);
pthread_create(&b_id, NULL, b, NULL);
pthread_create(&c_id, NULL, c, NULL);
pthread_join(a_id, NULL);
pthread_join(b_id, NULL);
pthread_join(c_id, NULL);
printf("\n");
return 0;
}
void* a(void* ret){
printf("a");
return ret;
}
void* b(void* ret){
for(int i = 0; i < 10; i++){
sched_yield();
}
printf("b");
return ret;
}
void* c(void* ret){
for(int i = 0; i < 100; i++){
sched_yield();
}
printf("c");
return ret;
}
There's 4 cases:
a) the scheduler doesn't use multiplexing (e.g. doesn't use "round robin" but uses "highest priority thread that can run does run", or "earliest deadline first", or ...) and sched_yield() does nothing.
b) the scheduler does use multiplexing in theory, but you have more CPUs than threads so the multiplexing doesn't actually happen, and sched_yield() does nothing. Note: With 16 CPUs and 2 threads, this is likely what you'd get for "default scheduling policy" on an OS like Linux - the sched_yield() just does a "Hrm, no other thread I could use this CPU for, so I guess the calling thread can keep using the same CPU!").
c) the scheduler does use multiplexing and there's more threads than CPUs, but to improve performance (avoid task switches) the scheduler designer decided that sched_yield() does nothing.
d) sched_yield() does cause a task switch (yielding the CPU to some other task), but that is not enough to do any kind of synchronization on its own (e.g. you'd need an atomic variable or something for the actual synchronization - maybe like "while( atomic_variable_not_set_by_other_thread ) { sched_yield(); }). Note that with an atomic variable (introduced in C11) it'd work without sched_yield() - the sched_yield() (if it does anything) merely makes busy waiting less awful/wasteful.
Essentially I'm unsure of how, using only sched_yield(), to
synchronize these threads given everything I could find and
troubleshoot with online.
That would be because sched_yield() is not well suited to the task. As I wrote in comments, sched_yield() is about scheduling, not synchronization. There is a relationship between the two, in the sense that synchronization events affect which threads are eligible to run, but that goes in the wrong direction for your needs.
You are probably looking at the problem from the wrong end. You need each of your threads to wait to execute until it is their turn, and for them to do that, they need some mechanism to convey information among them about whose turn it is. There are several alternatives for that, but if "only sched_yield()" is taken to mean that no library functions other than sched_yield() may be used for that purpose then a shared variable seems the expected choice. The starting point should therefore be how you could use a shared variable to make the threads take turns in the appropriate order.
Flawed starting point
Here is a naive approach that might spring immediately to mind:
/* FLAWED */
void *b(void *data){
char *whose_turn = data;
while (*whose_turn != 'b') {
// nothing?
}
printf("b");
*whose_turn = 'c';
return NULL;
}
That is, the thread executes a busy loop, monitoring the shared variable to await it taking a value signifying that the thread should proceed. When it has done its work, the thread modifies the variable to indicate that the next thread may proceed. But there are several problems with that, among them:
Supposing that at least one other thread writes to the object designated by *whose_turn, the program contains a data race, and therefore its behavior is undefined. As a practical matter, a thread that once entered the body of the loop in that function might loop infinitely, notwithstanding any action by other threads.
Without making additional assumptions about thread scheduling, such as a fairness policy, it is not safe to assume that the thread that will make the needed modification to the shared variable will be scheduled in bounded time.
While a thread is executing the loop in that function, it prevents any other thread from executing on the same core, yet it cannot make progress until some other thread takes action. To the extent that we can assume preemptive thread scheduling, this is an efficiency issue and contributory to (2). However, if we assume neither preemptive thread scheduling nor the threads being scheduled each on a separate core then this is an invitation to deadlock.
Possible improvements
The conventional and most appropriate way to do that in a pthreads program is with the use of a mutex and condition variable. Properly implemented, that resolves the data race (issue 1) and it ensures that other threads get a chance to run (issue 3). If that leaves no other threads eligible to run besides the one that will modify the shared variable then it also addresses issue 2, to the extent that the scheduler is assumed to grant any CPU to the process at all.
But you are forbidden to do that, so what else is available? Well, you could make the shared variable _Atomic. That would resolve the data race, and in practice it would likely be sufficient for the wanted thread ordering. In principle, however, it does not resolve issue 3, and as a practical matter, it does not use sched_yield(). Also, all that busy-looping is wasteful.
But wait! You have a clue in that you are told to use sched_yield(). What could that do for you? Suppose you insert a call to sched_yield() in the body of the busy loop:
/* (A bit) better */
void* b(void *data){
char *whose_turn = data;
while (*whose_turn != 'b') {
sched_yield();
}
printf("b");
*whose_turn = 'c';
return NULL;
}
That resolves issues 2 and 3, explicitly affording the possibility for other threads to run and putting the calling thread at the tail of the scheduler's thread list. Formally, it does not resolve issue 1 because sched_yield() has no documented effect on memory ordering, but in practice, I don't think it can be implemented without a (full) memory barrier. If you are allowed to use atomic objects then combining an atomic shared variable with sched_yield() would tick all three boxes. Even then, however, there would still be a bunch of wasteful busy-looping.
Final remarks
Note well that pthread_join() is a synchronization function, thus, as I understand the task, you may not use it to ensure that the main thread's output is printed last.
Note also that I have not spoken to how the main() function would need to be modified to support the approach I have suggested. Changes would be needed for that, and they are left as an exercise.
I’m reading up on pthread.h; the condition variable related functions (like pthread_cond_wait(3)) require a mutex as an argument. Why? As far as I can tell, I’m going to be creating a mutex just to use as that argument? What is that mutex supposed to do?
It's just the way that condition variables are (or were originally) implemented.
The mutex is used to protect the condition variable itself. That's why you need it locked before you do a wait.
The wait will "atomically" unlock the mutex, allowing others access to the condition variable (for signalling). Then when the condition variable is signalled or broadcast to, one or more of the threads on the waiting list will be woken up and the mutex will be magically locked again for that thread.
You typically see the following operation with condition variables, illustrating how they work. The following example is a worker thread which is given work via a signal to a condition variable.
thread:
initialise.
lock mutex.
while thread not told to stop working:
wait on condvar using mutex.
if work is available to be done:
do the work.
unlock mutex.
clean up.
exit thread.
The work is done within this loop provided that there is some available when the wait returns. When the thread has been flagged to stop doing work (usually by another thread setting the exit condition then kicking the condition variable to wake this thread up), the loop will exit, the mutex will be unlocked and this thread will exit.
The code above is a single-consumer model as the mutex remains locked while the work is being done. For a multi-consumer variation, you can use, as an example:
thread:
initialise.
lock mutex.
while thread not told to stop working:
wait on condvar using mutex.
if work is available to be done:
copy work to thread local storage.
unlock mutex.
do the work.
lock mutex.
unlock mutex.
clean up.
exit thread.
which allows other consumers to receive work while this one is doing work.
The condition variable relieves you of the burden of polling some condition instead allowing another thread to notify you when something needs to happen. Another thread can tell that thread that work is available as follows:
lock mutex.
flag work as available.
signal condition variable.
unlock mutex.
The vast majority of what are often erroneously called spurious wakeups was generally always because multiple threads had been signalled within their pthread_cond_wait call (broadcast), one would return with the mutex, do the work, then re-wait.
Then the second signalled thread could come out when there was no work to be done. So you had to have an extra variable indicating that work should be done (this was inherently mutex-protected with the condvar/mutex pair here - other threads needed to lock the mutex before changing it however).
It was technically possible for a thread to return from a condition wait without being kicked by another process (this is a genuine spurious wakeup) but, in all my many years working on pthreads, both in development/service of the code and as a user of them, I never once received one of these. Maybe that was just because HP had a decent implementation :-)
In any case, the same code that handled the erroneous case also handled genuine spurious wakeups as well since the work-available flag would not be set for those.
A condition variable is quite limited if you could only signal a condition, usually you need to handle some data that's related to to condition that was signalled. Signalling/wakeup have to be done atomically in regards to achieve that without introducing race conditions, or be overly complex
pthreads can also give you , for rather technical reasons, a spurious wakeup . That means you need to check a predicate, so you can be sure the condition actually was signalled - and distinguish that from a spurious wakeup. Checking such a condition in regards to waiting for it need to be guarded - so a condition variable needs a way to atomically wait/wake up while locking/unlocking a mutex guarding that condition.
Consider a simple example where you're notified that some data are produced. Maybe another thread made some data that you want, and set a pointer to that data.
Imagine a producer thread giving some data to another consumer thread through a 'some_data'
pointer.
while(1) {
pthread_cond_wait(&cond); //imagine cond_wait did not have a mutex
char *data = some_data;
some_data = NULL;
handle(data);
}
you'd naturally get a lot of race condition, what if the other thread did some_data = new_data right after you got woken up, but before you did data = some_data
You cannot really create your own mutex to guard this case either .e.g
while(1) {
pthread_cond_wait(&cond); //imagine cond_wait did not have a mutex
pthread_mutex_lock(&mutex);
char *data = some_data;
some_data = NULL;
pthread_mutex_unlock(&mutex);
handle(data);
}
Will not work, there's still a chance of a race condition in between waking up and grabbing the mutex. Placing the mutex before the pthread_cond_wait doesn't help you, as you will now
hold the mutex while waiting - i.e. the producer will never be able to grab the mutex.
(note, in this case you could create a second condition variable to signal the producer that you're done with some_data - though this will become complex, especially so if you want many producers/consumers.)
Thus you need a way to atomically release/grab the mutex when waiting/waking up from the condition. That's what pthread condition variables does, and here's what you'd do:
while(1) {
pthread_mutex_lock(&mutex);
while(some_data == NULL) { // predicate to acccount for spurious wakeups,would also
// make it robust if there were several consumers
pthread_cond_wait(&cond,&mutex); //atomically lock/unlock mutex
}
char *data = some_data;
some_data = NULL;
pthread_mutex_unlock(&mutex);
handle(data);
}
(the producer would naturally need to take the same precautions, always guarding 'some_data' with the same mutex, and making sure it doesn't overwrite some_data if some_data is currently != NULL)
POSIX condition variables are stateless. So it is your responsibility to maintain the state. Since the state will be accessed by both threads that wait and threads that tell other threads to stop waiting, it must be protected by a mutex. If you think you can use condition variables without a mutex, then you haven't grasped that condition variables are stateless.
Condition variables are built around a condition. Threads that wait on a condition variable are waiting for some condition. Threads that signal condition variables change that condition. For example, a thread might be waiting for some data to arrive. Some other thread might notice that the data has arrived. "The data has arrived" is the condition.
Here's the classic use of a condition variable, simplified:
while(1)
{
pthread_mutex_lock(&work_mutex);
while (work_queue_empty()) // wait for work
pthread_cond_wait(&work_cv, &work_mutex);
work = get_work_from_queue(); // get work
pthread_mutex_unlock(&work_mutex);
do_work(work); // do that work
}
See how the thread is waiting for work. The work is protected by a mutex. The wait releases the mutex so that another thread can give this thread some work. Here's how it would be signalled:
void AssignWork(WorkItem work)
{
pthread_mutex_lock(&work_mutex);
add_work_to_queue(work); // put work item on queue
pthread_cond_signal(&work_cv); // wake worker thread
pthread_mutex_unlock(&work_mutex);
}
Notice that you need the mutex to protect the work queue. Notice that the condition variable itself has no idea whether there's work or not. That is, a condition variable must be associated with a condition, that condition must be maintained by your code, and since it's shared among threads, it must be protected by a mutex.
Not all condition variable functions require a mutex: only the waiting operations do. The signal and broadcast operations do not require a mutex. A condition variable also is not permanently associated with a specific mutex; the external mutex does not protect the condition variable. If a condition variable has internal state, such as a queue of waiting threads, this must be protected by an internal lock inside the condition variable.
The wait operations bring together a condition variable and a mutex, because:
a thread has locked the mutex, evaluated some expression over shared variables and found it to be false, such that it needs to wait.
the thread must atomically move from owning the mutex, to waiting on the condition.
For this reason, the wait operation takes as arguments both the mutex and condition: so that it can manage the atomic transfer of a thread from owning the mutex to waiting, so that the thread does not fall victim to the lost wake up race condition.
A lost wakeup race condition will occur if a thread gives up a mutex, and then waits on a stateless synchronization object, but in a way which is not atomic: there exists a window of time when the thread no longer has the lock, and has not yet begun waiting on the object. During this window, another thread can come in, make the awaited condition true, signal the stateless synchronization and then disappear. The stateless object doesn't remember that it was signaled (it is stateless). So then the original thread goes to sleep on the stateless synchronization object, and does not wake up, even though the condition it needs has already become true: lost wakeup.
The condition variable wait functions avoid the lost wake up by making sure that the calling thread is registered to reliably catch the wakeup before it gives up the mutex. This would be impossible if the condition variable wait function did not take the mutex as an argument.
I do not find the other answers to be as concise and readable as this page. Normally the waiting code looks something like this:
mutex.lock()
while(!check())
condition.wait(mutex) # atomically unlocks mutex and sleeps. Calls
# mutex.lock() once the thread wakes up.
mutex.unlock()
There are three reasons to wrap the wait() in a mutex:
without a mutex another thread could signal() before the wait() and we'd miss this wake up.
normally check() is dependent on modification from another thread, so you need mutual exclusion on it anyway.
to ensure that the highest priority thread proceeds first (the queue for the mutex allows the scheduler to decide who goes next).
The third point is not always a concern - historical context is linked from the article to this conversation.
Spurious wake-ups are often mentioned with regard to this mechanism (i.e. the waiting thread is awoken without signal() being called). However, such events are handled by the looped check().
Condition variables are associated with a mutex because it is the only way it can avoid the race that it is designed to avoid.
// incorrect usage:
// thread 1:
while (notDone) {
pthread_mutex_lock(&mutex);
bool ready = protectedReadyToRunVariable
pthread_mutex_unlock(&mutex);
if (ready) {
doWork();
} else {
pthread_cond_wait(&cond1); // invalid syntax: this SHOULD have a mutex
}
}
// signalling thread
// thread 2:
prepareToRunThread1();
pthread_mutex_lock(&mutex);
protectedReadyToRuNVariable = true;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond1);
Now, lets look at a particularly nasty interleaving of these operations
pthread_mutex_lock(&mutex);
bool ready = protectedReadyToRunVariable;
pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&mutex);
protectedReadyToRuNVariable = true;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond1);
if (ready) {
pthread_cond_wait(&cond1); // uh o!
At this point, there is no thread which is going to signal the condition variable, so thread1 will wait forever, even though the protectedReadyToRunVariable says it's ready to go!
The only way around this is for condition variables to atomically release the mutex while simultaneously starting to wait on the condition variable. This is why the cond_wait function requires a mutex
// correct usage:
// thread 1:
while (notDone) {
pthread_mutex_lock(&mutex);
bool ready = protectedReadyToRunVariable
if (ready) {
pthread_mutex_unlock(&mutex);
doWork();
} else {
pthread_cond_wait(&mutex, &cond1);
}
}
// signalling thread
// thread 2:
prepareToRunThread1();
pthread_mutex_lock(&mutex);
protectedReadyToRuNVariable = true;
pthread_cond_signal(&mutex, &cond1);
pthread_mutex_unlock(&mutex);
The mutex is supposed to be locked when you call pthread_cond_wait; when you call it it atomically both unlocks the mutex and then blocks on the condition. Once the condition is signaled it atomically locks it again and returns.
This allows the implementation of predictable scheduling if desired, in that the thread that would be doing the signalling can wait until the mutex is released to do its processing and then signal the condition.
It appears to be a specific design decision rather than a conceptual need.
Per the pthreads docs the reason that the mutex was not separated is that there is a significant performance improvement by combining them and they expect that because of common race conditions if you don't use a mutex, it's almost always going to be done anyway.
https://linux.die.net/man/3/pthread_cond_wait
Features of Mutexes and Condition Variables
It had been suggested that the mutex acquisition and release be
decoupled from condition wait. This was rejected because it is the
combined nature of the operation that, in fact, facilitates realtime
implementations. Those implementations can atomically move a
high-priority thread between the condition variable and the mutex in a
manner that is transparent to the caller. This can prevent extra
context switches and provide more deterministic acquisition of a mutex
when the waiting thread is signaled. Thus, fairness and priority
issues can be dealt with directly by the scheduling discipline.
Furthermore, the current condition wait operation matches existing
practice.
There are a tons of exegeses about that, yet I want to epitomize it with an example following.
1 void thr_child() {
2 done = 1;
3 pthread_cond_signal(&c);
4 }
5 void thr_parent() {
6 if (done == 0)
7 pthread_cond_wait(&c);
8 }
What's wrong with the code snippet? Just ponder somewhat before going ahead.
The issue is genuinely subtle. If the parent invokes
thr_parent() and then vets the value of done, it will see that it is 0 and
thus try to go to sleep. But just before it calls wait to go to sleep, the parent
is interrupted between lines of 6-7, and the child runs. The child changes the state variable
done to 1 and signals, but no thread is waiting and thus no thread is
woken. When the parent runs again, it sleeps forever, which is really egregious.
What if they are carried out while acquired locks individually?
I made an exercice in class if you want a real example of condition variable :
#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
#include "unistd.h"
int compteur = 0;
pthread_cond_t varCond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex_compteur;
void attenteSeuil(arg)
{
pthread_mutex_lock(&mutex_compteur);
while(compteur < 10)
{
printf("Compteur : %d<10 so i am waiting...\n", compteur);
pthread_cond_wait(&varCond, &mutex_compteur);
}
printf("I waited nicely and now the compteur = %d\n", compteur);
pthread_mutex_unlock(&mutex_compteur);
pthread_exit(NULL);
}
void incrementCompteur(arg)
{
while(1)
{
pthread_mutex_lock(&mutex_compteur);
if(compteur == 10)
{
printf("Compteur = 10\n");
pthread_cond_signal(&varCond);
pthread_mutex_unlock(&mutex_compteur);
pthread_exit(NULL);
}
else
{
printf("Compteur ++\n");
compteur++;
}
pthread_mutex_unlock(&mutex_compteur);
}
}
int main(int argc, char const *argv[])
{
int i;
pthread_t threads[2];
pthread_mutex_init(&mutex_compteur, NULL);
pthread_create(&threads[0], NULL, incrementCompteur, NULL);
pthread_create(&threads[1], NULL, attenteSeuil, NULL);
pthread_exit(NULL);
}
I am new to C and wanted to know about race conditions. I found this on the internet and it asked to find the race condition, and a solution to it.
My analysis is that the race condition is in the create-thread() method has the race condition, specifically in the if-else statement. So when the method is being accessed another thread could be created or removed during the check-and-act and the thread_amt would be off.
In order to not have the race condition, then lock the if-else using mutex, semaphores, etc?
Can anyone correct me if I am wrong, and could possibly show me how to implement mutex?
#define MAXT 255
int threads_amt = 0;
int create-thread() // create a new thread
{
int tid;
if (threads_amt == MAXT) return -1;
else
{
threads_amt++;
return tid;
}
}
void release-thread()
{
/* release thread resources */
--threads_amt;
}
Yeah, the race condition in this case happens because you have no guarantee that the checking and the manipulation of threads_amt are going to happen with no interruption/execution of another thread.
Three solutions off the top of my head:
1) Force mutual exclusion to that part of code using a binary semaphore (or mutex) to protect the if-else part.
2) Use a semaphore with initial value MAXT, and then, upon calling create_thread (mind, you can't use hyphens in function names!), use "wait()" (depending on the type of semaphore, it could have different names (such as sem_wait())). After that, create the thread. When calling release_thread(), simply use "signal()" (sem_post(), when using semaphore.h).
3) This is more of an "hardware" solution: you could assume that you are given an atomic function that performs the entire if-else part, and therefore avoids any race condition problem.
Of these solutions, the "easiest" one (based on the code you already have) is the first one.
Let's use semaphore.h's semaphores:
#define MAXT 255
// Global semaphore
sem_t s;
int threads_amt = 0;
int main () {
...
sem_init (&s, 0, 1); // init semaphore (initial value = 1)
...
}
int create_thread() // create a new thread
{
int tid;
sem_wait(&s);
if (threads_amt == MAXT) {
sem_post(&s); // the semaphore is now available
return -1;
}
else
{
threads_amt++;
sem_post(&s); // the semaphore is now available
return tid;
}
}
void release_thread()
{
/* release thread resources */
sem_wait(&s);
--threads_amt;
sem_post(&s);
}
This should work just fine.
I hope it's clear. If it's not, I suggest that you study how semaphores work (use the web, or buy some Operating System book). Also, you mentioned that you are new to C: IMHO you should start with something easier than this: semaphores aren't exactly the next thing you want to learn after the 'hello world' ;-)
The race condition is not in the if() statements.
It is with access to the variable threads_amt that is potentially changed and accessed at the same time in multiple threads.
Essentially, any thread that modifies the variable must have exclusive access to avoid a race condition. That means all code which modifies the variable or reads its value must be synchronised (e.g. grab a mutex first, release after). Readers don't necessarily need exclusive access (e.g. two threads reading at the same time won't necessarily affect each other) but writers do (so avoid reading a value while trying to change it in another thread) - such considerations can be opportunities to use synchronisation methods other than a mutex - for example, semaphores.
To use a mutex, it is necessary to create it first (e.g. during project startup). Then grab it when needed, and remember to release it when done. Every function should minimise the time that it holds the mutex, since other threads trying to grab the mutex will be forced to wait.
The trick is to make the grabbing and releasing of the mutex unconditional, wherever it occurs (i.e. avoid a function that grabs the mutex, being able to return without releasing it). That depends on how you structure each function.
The actual code for implementing depends on which threading library you're using (so you need to read the documentation) but the concepts are the same. All threading libraries have functions for creating, grabbing (or entering), and releasing mutexes, semaphores, etc etc.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
kill thread in pthread
Here after a source code containing a launch of thread and then after a while I want to kill it. How to do it ? Without make any change in the thread function
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
pthread_t test_thread;
void *thread_test_run (void *v) // I must not modify this function
{
int i=1;
while(1)
{
printf("into thread %d\r\n",i);
i++;
sleep(1);
}
return NULL
}
int main()
{
pthread_create(&test_thread, NULL, &thread_test_run, NULL);
sleep (20);
// Kill the thread here. How to do it?
// other function are called here...
return 0;
}
You can use pthread_cancel() to kill a thread:
int pthread_cancel(pthread_t thread);
Note that the thread might not get a chance to do necessary cleanups, for example, release a lock, free memory and so on..So you should first use pthread_cleanup_push() to add cleanup functions that will be called when the thread is cancelled. From man pthread_cleanup_push(3):
These functions manipulate the calling thread's stack of
thread-cancellation clean-up handlers. A clean-up handler is a
function that is automatically executed when a thread is cancelled (or
in various other circumstances described below); it might, for
example, unlock a mutex so that it becomes available to other threads
in the process.
Regarding the question of whether a thread will be cancelled if blocking or not, it's not guaranteed, note that the manual also mentions this:
A thread's cancellation type, determined by pthread_setcanceltype(3),
may be either asynchronous or deferred (the default for new
threads). Asynchronous cancelability means that the thread
can be canceled at any time (usually immediately, but the system does
not guarantee this). Deferred cancelability means that cancellation
will be delayed until the thread next calls a function that is a
cancellation point.
So this means that the only guaranteed behaviour is the the thread will be cancelled at a certain point after the call to pthread_cancel().
Note:
If you cannot change the thread code to add the cleanup handlers, then your only other choice is to kill the thread with pthread_kill(), however this is a very bad way to do it for the aforementioned reasons.
The short answer is this: With the cooperation of the code that thread is running, you may terminate it using any method it supports. Without the cooperation of the code that thread is running, you shouldn't even try it. What if the thread is holding a critical lock when you kill it? What if the thread has allocated memory and there is no other code to free that memory?
I am really at a loss here.
i read the MSDN articles thoroughly but still cant figure out what is going on.
my problem is this: when running a few processes with the following code all is working:
HANDLE m = CreateMutex(NULL, FALSE, L"MyMutex");
char c[20] = "2print";
for(int iter = 0; iter<100; ++iter) {
WaitForSingleObject(m,INFINITE);
for(int i=0;i<(int)strlen(c);++i) {
for(int j=0;j<10000;++j)
printf("%c",c[i]);
}
BOOL ok = ReleaseMutex(m);
}
CloseHandle(m);
that is, the different processes each printing at its own turn and releasing the mutex until all printing is done.
BUT changing the CreateMutex to: (bInitialOwner from FALSE to TRUE)
HANDLE m = CreateMutex(NULL, TRUE, L"MyMutex");
the first creator will not release the mutex! other processes are just sitting there.
what amazed me was, that by adding an additional releaseMutex, that is changing:
BOOL ok = ReleaseMutex(m);
into:
BOOL ok = ReleaseMutex(m);
ok = ReleaseMutex(m);
make it work!
i am really confused, why wouldnt the first creator release the mutex correctly?
i tried printing all the errors using GetLastError, and what i get seem reasonable, like ERROR_ALREADY_EXISTS for the creators following the first one, which is just what i expect (MSDN says that in this situation the bInitialOwner is simply ignored).
When you use bInitialOwner=TRUE, the mutex creator automatically acquires the mutex. Then when you call WaitForSingleObject, it acquired the mutex again. Since win32 mutexes are recursive mutexes, you must release once for each time you acquired the mutex - so two ReleaseMutex calls are needed for the initial creator (however every other thread must only release once!)
You can avoid this by either not using bInitialOwner, or by skipping the WaitForSingleObject on the first loop only if any only if GetLastError() != ERROR_ALREADY_EXISTS. You will need to call SetLastError(0) prior to CreateMutex to clear the error code if you choose the latter.
If you only need bInitialOwner for some kind of initial setup, it will simplify your code if you drop the mutex prior to entering the common loop. Otherwise, I would strongly recommend simply not using bInitialOwner, unless you have a compelling reason to do so.