The program creates four threads that each print a message with a unique id number. Like many threaded programs, it sometimes works correctly even though it contains an error. Can you spot the race condition?
#include#include #define N 4 void* hello (void* myID) { printf ("Hello from thread %d ", *(int *)myID); return NULL; } int main () { int j; pthread_t tid ; for (j = 0; j < N; j++) pthread_create (&tid , NULL, hello, (void *)&j); for (j = 0; j < N; j++) pthread_join (tid , NULL); }
If you see the error, be the first to post the solution and win the forum's ovation and fame forever.
連結已複製
#include#include #define N 4 DWORD WINAPI hello (LPVOID myID) { printf ("Hello from thread %d ", *(int *)myID); } int main (int argc, char* argv[]) { int j; HANDLE h ; DWORD rc; for (j = 0; j < N; j++) { h = CreateThread (0, 0, hello, (LPVOID)&j, 0, NULL); } rc = WaitForMultipleObjects (N, h, TRUE, INFINITE); }
Welcome to the forum! You're the first to join.
You're correct that variable j is incorrectly passed to the threaded function. It's the source of the race condition. You could fix the race condition using a critical section but that would serialize execution, which defeats the purpose of multithreading. There's a better solution that doesn't require synchronization.
Henry
I'm sure there are many ways to solve this problem of which my suggestion is only one.
int id; for (j = 0; j < N; j++) { id = j; pthread_create (&tid , NULL, hello, (void *)&id ); }
#include
#include
#define N 4
void* hello (void* myID)
{
printf ("Hello from thread %d ", (int)myID);
return NULL;
}
int main ()
{
int j;
pthread_t tid
for (j = 0; j < N; j++)
pthread_create (&tid
for (j = 0; j < N; j++)
pthread_join (tid
}
-Dale
To do this safely without serializing thread startup, the simplest thing is to build an array of these structures (if you know the thread count will be constant) or to dynamically create them otherwise. Essentially, it's the same as you handle the array of thread id's in your example code, just extended to the parameter or parameter block passed during thread creation.
"Command" is a useful design pattern here.
struct ICommand
{
virtual void execute () = 0;
};
it's easy to define a framework with something like
Thread *CreateThread (ICommand *cmd);
the command will be executed at thread launch and the instance deleted after execution
the client code will be typically like :
class HenryGCommand : public ICommand
{
const int id;
// typically way more data here
virtual void execute ()
{cout << "Hello from thread " << id << " ";}
public:
HenryGCommand (int vId) : id(vId) {}
};
void Test ()
{
Thread *t
for (int j=0; j
WaitFor(t,N,INFINITE);
}
Message Edited by intel.software.network.support on 12-09-2005 01:30 PM
Holy smokes this is old.. but I didn't see a good answer.. but maybe I missed it..
The problem with the code is that we pass the variable J from the caller to the thread by reference. Thread starts require a variable amount of time.. sometimes its fast sometimes it takes awhile.. (this depends if there is pooling, etc.) Because we pass by ref it is possible that, by the time the thread starts, the variable J has been incremented. If this happens we may get four lines saying thread 4 has started or some other erroneous values. J needs to be copied to the thread by value. There are many ways of doing this. Simply passing J in the VOID* would work since they are both 4 bytes.You could also create a class or struct and pass the value inside the pointer to this. However we accomplish this, it must be a separate value from the J that is being incremented by the starting thread.
Chris
