0

函数 pthreads 示例是PrintHello()线程安全的吗?我在网上找到了这类示例,但我不明白它们如何是线程安全的。另一方面,如果我在PrintHello()函数中的代码周围添加一个互斥锁,那么该示例将不会是多线程的,因为所有线程都会排队等待前一个线程退出PrintHello()函数。CreateThread()此外,将它移动到一个类也无济于事,因为它似乎不允许将成员静态声明为指向非静态函数的指针。有什么办法解决这个问题吗?

#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);
      }
   }
}
4

2 回答 2

6

由于您包括WinBase.h,我假设您使用的是 MSVC。MSVC CRT 长期以来一直支持多线程访问——事实上,当前版本的 MSVC 不再支持非线程安全的单线程 CRT。我相信 VS 2003 是支持单线程 CRT 的最后一个 MSVC 版本。

在多线程 CRT 中,函数是线程安全的,如果它们在内部访问全局数据,它们将相互同步。所以每个printf()执行的ProcessRequest()对于printf()其他线程中的其他调用都是原子的(实际上,锁是基于流的,所以printf()调用对于使用的其他 CRT 函数来说是原子的stdout)。

例外情况是,如果您使用明确记录为不使用锁的 I/O 函数(因此出于性能原因您可以自己同步它们),或者如果您定义_CRT_DISABLE_PERFCRIT_LOCKS在这种情况下 CRT 假定所有 I/O 将在单个线程上执行。

请参阅http://msdn.microsoft.com/en-us/library/ms235505.aspx

printf()POSIX 做出了类似的线程安全保证:

于 2013-05-13T08:17:22.703 回答
0

代码通常不是线程安全的;printf通常不是可重入的。(实现可以将重入作为附加功能添加到它,但我不知道有什么功能。)您必须围绕它添加某种保护。(在 Windows 下,一个所谓的CriticalSection就足够了。)

您还必须找到一个线程安全的替代方法sleep;我找不到任何说明它是可重入的文档(而 Posix 变体不是),但微软似乎没有记录一般的可重入。一个经典的解决方案是创建一个 Mutex,阻塞它,然后 WaitForSingleObject用所需的超时时间调用它; CreateWaitableTimer并且WaitForSingleObject应该也可以工作。(正如我所说,Microsoft 的文档非常缺乏;但WaitForSingleObject必须是安全的,因为它被设计为在等待互斥体时使用,除其他外。)

还要注意,除非您加入创建的线程,否则您可能会在 结束时运行main,并且该进程将在任何线程运行之前终止。(在 Windows 下,您可以使用WaitForSingleObjectWaitForMultipleObjects加入。)

一个更好的解决方案是标准线程,如果你有一个支持它们的编译器,或者 Boost threds,如果你没有。

于 2013-05-13T08:14:16.563 回答