Does this section of code require a mutex?
I am trying to implement a crude thread interrupt.
The 'interruptRequested' variable is being checked pretty often. In Operating Systems class we learned about starvation -- Is that possible here or in a similar situation? I know that the example program behaves as I would expect when I run it, but it could just be a fluke.
Here is a simplified version of what I'm doing:
//Compile with -lpthread
#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
using namespace std;
bool interruptRequested;
pthread_mutex_t spamMutex;
void *Spam(void *);
int main(int argc, char *argv[])
{
pthread_t tid;
interruptRequested = false;
unsigned long long int timeStarted = time(NULL);
pthread_create(&tid, NULL, Spam, NULL开发者_StackOverflow社区);
unsigned long long int difference = 0;
while (true)
{
pthread_yield();
difference = (time(NULL) - timeStarted);
if ( difference >= 5)//Spam the terminal for 5 seconds
{
//while (pthread_mutex_trylock(&spamMutex));
interruptRequested = true;
//pthread_mutex_unlock(&spamMutex);
break;
}
}
return 0;
}
void *Spam (void *arg)
{
while (true)
{
//while (pthread_mutex_trylock(&spamMutex));
if (interruptRequested == true)
{
//pthread_mutex_unlock(&spamMutex);
break;
}
//pthread_mutex_unlock(&spamMutex);
cout << "I'm an ugly elf" << endl;
pthread_yield();
}
interruptRequested = false;
pthread_exit (0);
}
Actually, in the real code I am not using the time difference approach. My program will be recieve a message from a server and at that point I need to interrupt the thread.
As written, this code is not necessarily guaranteed to work because the compiler might optimize away the check for interruptRequested
inside of the worker thread because it's never written inside of the function. This would mean that the generated code may just have a while (true)
loop in it (or something equivalent to it).
To prevent this from happening, you somehow need to ensure that the compiler recognizes that the variable might be modified elsewhere. You could do this by marking interruptRequested
volatile
, which indicates to the compiler that it shouldn't be optimized away. Using a mutex is also a good idea, because most compilers are smart enough to recognize that the use of a mutex indicates that the variables referenced inside of the mutex may be modified externally.
yes, you must first use a mutex to protect reads and writes to interruptRequested
, in respective blocks.
even if it appears to work as expected, it may not actually. a 99% success rate is not acceptable in software. as well, your test program is trivial - chances are good that it would (silently or mysteriously) fail in the real world.
using volatile (or atomics, in many cases) as a replacement for a lock is a bad idea. this model will eventually fail, although it often appears to work correctly under light loads. there are a few corner cases, but you should abandon associations of volatile being a replacement for a proper design which uses locking. in fact you can test this by making interruptRequested
an int
, and using only increment/decrement. under heavy loads - you can quickly exceed [0...1].
you will often use volatile and/or atomics when declaring/reading/writing interruptRequested (again, i recommend an int/inc/dec/bounds checks, especially while you are learning). if the reads and writes are all locked (which they should be in this case), using atomic reads/writes won't help.
regarding your program, conditions (pthread_cond_t
) may be a good choice.
I think in general shared data should be handled with mutex.
In this specific case only one thread updates the control variable, so it might be too much using a mutex. You can put a time sleep in the active loop of few milliseconds to make the main loop active from time to time.
精彩评论