首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程安全的CreateThread?

线程安全的CreateThread?
EN

Stack Overflow用户
提问于 2013-05-13 15:44:27
回答 2查看 1K关注 0票数 0

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

代码语言:javascript
复制
#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);
      }
   }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-05-13 16:17:23

由于您包含了WinBase.h,因此我假设您使用的是MSVC。MSVC CRT长期以来一直支持多线程访问-事实上,MSVC的当前版本不再支持非threadsafe的单线程CRT。我相信VS2003是支持单线程CRT的MSVC的最后一个版本。

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

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

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

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

  • http://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html

引用(FILE *)对象的所有函数(名称以_unlocked结尾的函数除外)在内部使用flockfile()和funlockfile()来获得这些(FILE *)对象的所有权。

  • http://newsgroups.derkeiler.com/Archive/Comp/comp.programming.threads/2009-06/msg00058.html ( David Butenhof的帖子):

POSIX/UNIX要求printf()本身是原子的;从不同的线程对printf()的两个并行调用可以混合它们的数据是不合法的。但这两个写入可能会以任一顺序显示在输出上。

票数 6
EN

Stack Overflow用户

发布于 2013-05-13 16:14:17

代码通常不是线程安全的;printf通常不是可重入的。(一个实现可以将reentrace作为一个附加功能添加到其中,但我不知道有哪一个是这样做的。)你必须在它周围添加一些保护措施。(在Windows下,一个所谓的CriticalSection应该就足够了。)

你还必须找到一个线程安全的sleep的替代品;我找不到任何文档说它是可重入的(而Posix变体不是),但微软似乎没有一般的文档可重入。一种经典的解决方案是创建一个互斥锁,阻塞它,然后用所需的超时时间在它上面调用WaitForSingleObjectCreateWaitableTimerWaitForSingleObject也应该可以工作。(正如我所说的,微软的文档非常有缺陷;但WaitForSingleObject必须是安全的,因为它被设计为在等待互斥时使用。)

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

一个更好的解决方案是使用标准线程,如果你有一个支持它们的编译器,或者如果你不支持的话,可以使用Boost them。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16517067

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档