Reputation:
Is the PrintHello()
function pthreads example thread-safe? I find these kind of examples online but I don't understand how they can be thread-safe. On the other hand, if I add a mutex around the code in PrintHello()
function then the example would not be multithreaded as all threads would queue in wait for the previous thread to exit the PrintHello()
function. Also, moving it to a class would not help as the member would have to be statically declared as pointers to non-static functions is not allowed with CreateThread()
it seems. Any way of solving this?
#include <WinBase.h>
#include <stdio.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#define NUM_THREADS 500
DWORD PrintHello(LPVOID oHdlRequest)
{
long tid;
tid = (long)GetCurrentThreadId();
/* randomly sleep between 1 and 10 seconds */
int sleepTime = rand() % 10 + 1;
sleep(sleepTime);
printf("Hello World! It's me, thread #%ld!\n", tid);
return 0;
}
int main (int argc, char *argv[])
{
/* initialize random seed: */
srand (time(NULL));
HANDLE threads[NUM_THREADS];
long t;
DWORD nThreadID;
for(t=0; t<NUM_THREADS; t++){
printf("In main: creating thread %ld\n", t);
threads[t] = CreateThread(
// Default security
NULL,
// Default stack size
0,
// Function to execute
(LPTHREAD_START_ROUTINE)&PrintHello,
// Thread argument
NULL,
// Start the new thread immediately
0,
// Thread Id
&nThreadID
);
if (!threads[t]){
printf("ERROR; return code from CreateThread() is %d\n", GetLastError());
exit(-1);
}
}
}
Upvotes: 0
Views: 1152
Reputation: 340258
Since you're including WinBase.h
, I'll assume that you're using MSVC. MSVC CRT has long supported multithreaded access - in fact, current versions of MSVC no longer support a single threaded CRT that isn't threadsafe. I believe that VS 2003 is the last version of MSVC that supported the single threaded CRT.
In the multithreaded CRT, functions are threadsafe and if they access global data internally they will synchronize among themselves. So each printf()
executed in ProcessRequest()
will be atomic with respect to other printf()
calls in other threads (actually, the locks are based on streams, so the printf()
calls will be atomic with respect to other CRT functions that use stdout
).
The exceptions to this are if you use I/O functions that are explicitly documented to not take locks (so you can synchronize on them yourself for performance reasons), or if you define _CRT_DISABLE_PERFCRIT_LOCKS
in which case the CRT assumes that all I/O will be performed on a single thread.
See http://msdn.microsoft.com/en-us/library/ms235505.aspx
POSIX makes similar guarantees that printf()
will be threadsafe:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html
All functions that reference (FILE *) objects, except those with names ending in _unlocked, shall behave as if they use flockfile() and funlockfile() internally to obtain ownership of these (FILE *) objects.
http://newsgroups.derkeiler.com/Archive/Comp/comp.programming.threads/2009-06/msg00058.html (A post by David Butenhof):
POSIX/UNIX requires that printf() itself be atomic; it's not legal that two parallel calls to printf() from separate threads can mix their data. But those two writes may appear on the output in either order.
Upvotes: 6
Reputation: 153939
The code is not thread-safe in general; printf
is not normally
reentrant. (An implementation could add reentrace to it as
an additional feature, but I don't know of any which do.) You
must add some sort of protection around it. (Under Windows,
a so called CriticalSection
should be sufficient.)
You'll also have to find a thread safe alternative to sleep
;
I can't find any documentation which says that it is reentrant
(and the Posix variant isn't), but Microsoft doesn't seem to
document reentrance in general. A classical solution for this
would be to create a Mutex, block it, and then call
WaitForSingleObject
on it with the desired timeout;
CreateWaitableTimer
and WaitForSingleObject
should work as
well. (As I said, Microsoft's documentation is very deficient;
but WaitForSingleObject
must be safe, since it is des igned to
be used when waiting for a mutex, among other things.)
Note too that unless you join the created threads, you'll
probably run off the end of main
, and the process will
terminate before any of the threads will have run. (Under
Windows, you can use WaitForSingleObject
or
WaitForMultipleObjects
to join.)
An even better solution would be to the standard threads, if you have a compiler which supports them, or Boost threds, if you don't.
Upvotes: 0