_beginThreadex创建多线程解读

来源:互联网 发布:淘宝二手ipad哪家靠谱 编辑:程序博客网 时间:2024/06/05 17:40

http://blog.csdn.net/wojiushiwo987/article/details/7720656

_beginThreadex创建多线程解读

一、需要的头文件支持

#include <process.h> // for _beginthread()

需要的设置:ProjectàSetting-->C/C++-->User run-time library 选择Debug Multithreaded 或者Multithreaded。即使用: MT或MTD。

源码如下:

[cpp] view plaincopyprint?
  1. #include <stdio.h>
  2. #include <string> // for STL string class
  3. #include <windows.h> // for HANDLE
  4. #include <process.h> // for _beginthread()
  5. using namespace std;
  6. class ThreadX
  7. {
  8. private:
  9. int loopStart;
  10. int loopEnd;
  11. int dispFrequency;
  12. public:
  13. string threadName;
  14. ThreadX( int startValue, int endValue, int frequency )
  15. {
  16. loopStart = startValue;
  17. loopEnd = endValue;
  18. dispFrequency = frequency;
  19. }
  20. static unsigned __stdcall ThreadStaticEntryPoint(void * pThis)
  21. {
  22. ThreadX * pthX = (ThreadX*)pThis; // the tricky cast
  23. pthX->ThreadEntryPoint(); // now call the true entry-point-function
  24. return 1; // the thread exit code
  25. }
  26. void ThreadEntryPoint()
  27. {
  28. for (int i = loopStart; i <= loopEnd; ++i)
  29. {
  30. if (i % dispFrequency == 0)
  31. {
  32. printf( "%s: i = %d\n", threadName.c_str(), i );
  33. }
  34. }
  35. printf( "%s thread terminating\n", threadName.c_str() );
  36. }
  37. };
  38. int main()
  39. {
  40. ThreadX * o1 = new ThreadX( 0, 1, 2000 );
  41. HANDLE hth1;
  42. unsigned uiThread1ID;
  43. hth1 = (HANDLE)_beginthreadex( NULL,// security
  44. 0, // stack size
  45. ThreadX::ThreadStaticEntryPoint,
  46. o1, // arg list
  47. CREATE_SUSPENDED, // so we can later call ResumeThread()
  48. &uiThread1ID );
  49. if ( hth1 == 0 )
  50. printf("Failed to create thread 1\n");
  51. DWORD dwExitCode;
  52. GetExitCodeThread( hth1, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259
  53. printf( "initial thread 1 exit code = %u\n", dwExitCode );
  54. o1->threadName = "t1";
  55. ThreadX * o2 = new ThreadX( -100000, 0, 2000 );
  56. HANDLE hth2;
  57. unsigned uiThread2ID;
  58. hth2 = (HANDLE)_beginthreadex( NULL,// security
  59. 0, // stack size
  60. ThreadX::ThreadStaticEntryPoint,
  61. o2, // arg list
  62. CREATE_SUSPENDED, // so we can later call ResumeThread()
  63. &uiThread2ID );
  64. if ( hth2 == 0 )
  65. printf("Failed to create thread 2\n");
  66. GetExitCodeThread( hth2, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259
  67. printf( "initial thread 2 exit code = %u\n", dwExitCode );
  68. o2->threadName = "t2";
  69. ResumeThread( hth1 ); // serves the purpose of Jaeschke's t1->Start()
  70. ResumeThread( hth2 );
  71. WaitForSingleObject( hth1, INFINITE );
  72. WaitForSingleObject( hth2, INFINITE );
  73. GetExitCodeThread( hth1, &dwExitCode );
  74. printf( "thread 1 exited with code %u\n", dwExitCode );
  75. GetExitCodeThread( hth2, &dwExitCode );
  76. printf( "thread 2 exited with code %u\n", dwExitCode );
  77. CloseHandle( hth1 );
  78. CloseHandle( hth2 );
  79. delete o1;
  80. o1 = NULL;
  81. delete o2;
  82. o2 = NULL;
  83. printf("Primary thread terminating.\n");
  84. return 0;
  85. }


二、解释

(1)如果你正在编写C/C++代码,决不应该调用CreateThread。相反,应该使用VisualC++运行期库函数_beginthreadex,退出也应该使用_endthreadex。如果不使用Microsoft的VisualC++编译器,你的编译器供应商有它自己的CreateThread替代函数。不管这个替代函数是什么,你都必须使用。

(2)因为_beginthreadex和_endthreadex是CRT线程函数,所以必须注意编译选项runtimelibaray的选择,使用MTMTD。[MultiThreaded , Debug MultiThreaded]。

(3)_beginthreadex函数的参数列表与CreateThread函数的参数列表是相同的,但是参数名和类型并不完全相同。这是因为Microsoft的C/C++运行期库的开发小组认为,C/C++运行期函数不应该对Windows数据类型有任何依赖。_beginthreadex函数也像CreateThread那样,返回新创建的线程的句柄。

下面是关于_beginthreadex的一些要点:

1)每个线程均获得由C/C++运行期库的堆栈分配的自己的tiddata内存结构。(tiddata结构位于Mtdll.h文件中的VisualC++源代码中)。

2)传递给_beginthreadex的线程函数的地址保存在tiddata内存块中。传递给该函数的参数也保存在该数据块中。

3)_beginthreadex确实从内部调用CreateThread,因为这是操作系统了解如何创建新线程的唯一方法。

4)当调用CreatetThread时,它被告知通过调用_threadstartex而不是pfnStartAddr来启动执行新线程。还有,传递给线程函数的参数是tiddata结构而不是pvParam的地址。

5)如果一切顺利,就会像CreateThread那样返回线程句柄。如果任何操作失败了,便返回NULL。

(4)_endthreadex的一些要点:

C运行期库的_getptd函数内部调用操作系统的TlsGetValue函数,该函数负责检索调用线程的tiddata内存块的地址。

然后该数据块被释放,而操作系统的ExitThread函数被调用,以便真正撤消该线程。当然,退出代码要正确地设置和传递。

(5)虽然也提供了简化版的的_beginthread和_endthread,但是可控制性太差,所以一般不使用。

(6)线程handle因为是内核对象,所以需要在最后closehandle。

(7)更多的API:

HANDLE GetCurrentProcess();

HANDLE GetCurrentThread();

DWORD GetCurrentProcessId();

DWORD GetCurrentThreadId()。

DWORD SetThreadIdealProcessor(HANDLE hThread,DWORDdwIdealProcessor);

BOOL SetThreadPriority(HANDLE hThread,int nPriority);

BOOL SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);

BOOL GetThreadContext(HANDLE hThread,PCONTEXTpContext);

BOOL SwitchToThread();

三、注意

(1)C++主线程的终止,同时也会终止所有主线程创建的子线程,不管子线程有没有执行完毕。所以上面的代码中如果不调用WaitForSingleObject,则2个子线程t1和t2可能并没有执行完毕或根本没有执行。

(2)如果某线程挂起,然后有调用WaitForSingleObject等待该线程,就会导致死锁。所以上面的代码如果不调用resumethread,则会死锁。

四、为什么用_beginthreadex而不是CreateThread?

为什么要用C运行时库的_beginthreadex代替操作系统的CreateThread来创建线程?

来源自自19997MSJ杂志的《Win32 Q&A》栏目

你也许会说我一直用CreateThread来创建线程,一直都工作得好好的,为什么要用_beginthreadex来代替CreateThread,下面让我来告诉你为什么。

回答一个问题可以有两种方式,一种是简单的,一种是复杂的。

如果你不愿意看下面的长篇大论,那我可以告诉你简单的答案:_beginthreadex在内部调用了CreateThread,在调用之前_beginthreadex做了很多的工作,从而使得它比CreateThread更安全

 

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 u盘装系统就一个图标怎么办 淘宝买了东西退货客服不理人怎么办 微信10w限额满了怎么办 微信身份证实名认证超出限额怎么办 微信信用卡消费超过当日限额怎么办 淘宝客服同意退货卖家拒绝怎么办 微信钱包充值话费不到帐怎么办 京东买的显示器过保坏了怎么办 支付宝充话费充错号码是空号怎么办 京东充话费充错了号码该怎么办 微信红包充话费不到账怎么办 支付宝充话费等待第三方发货怎么办 微信充话费显示成功但没收到怎么办 微信退款一直在退款中怎么办 文件大于100发不了微信怎么办 微信的传送文件大于100怎么办 微信钱包话费充值错误怎么办 微信转账到不了账也退不回是怎么办 求人办事微信发红包对方不收怎么办 微信上交了订金对方不退怎么办 交通事故对方伤员堵大门搂腿怎么办 电脑开机桌面文件都没了怎么办 qq飞车手游队长换了微信群怎么办 qq飞车手游登录授权失败怎么办 安装时提示安装包发现错误怎么办 苹果6p升级系统验证失败怎么办 w10开不了机无限重启怎么办 微信朋友圈里的表情图打不开怎么办 金立手机微信启动录音被拒绝怎么办 微信帐号解封后漂流瓶不能用怎么办 微信怎么在电脑上登不上去怎么办 玩旧版60级魔兽经常花屏怎么办? 我的世界手机版物品栏不见了怎么办 苹果手机掉进水里出现花屏该怎么办 球球大作战还没进去停止运行怎么办 ps3 e3硬破芯片坏了怎么办 电话打开后页面上没有东西怎么办 WPS在电脑安装后卸载不了怎么办 ps总要以管理员的身份打开怎么办 3d关的慢保存慢怎么办 无法与服务器建立可靠的连接怎么办