概述
_beginThreadex创建多线程解读
一、需要的头文件支持
需要的设置:ProjectàSetting-->C/C++-->User run-time library 选择Debug Multithreaded 或者Multithreaded。即使用: MT或MTD。
源码如下:
- #include
- #include
// for STL string class - #include
// for HANDLE - #include
// for _beginthread() - using
namespace std; -
- class
ThreadX - {
- private:
-
int loopStart; -
int loopEnd; -
int dispFrequency; - public:
-
string threadName; -
-
ThreadX( int startValue, int endValue, int frequency ) -
{ -
loopStart = startValue; -
loopEnd = endValue; -
dispFrequency = frequency; -
} -
-
static unsigned __stdcall ThreadStaticEntryPoint(void * pThis) -
{ -
ThreadX * pthX = (ThreadX*)pThis; // the tricky cast -
pthX->ThreadEntryPoint(); // now call the true entry-point-function -
return 1; // the thread exit code -
} -
-
void ThreadEntryPoint() -
{ -
for (int i = loopStart; i <= loopEnd; ++i) -
{ -
if (i % dispFrequency == 0) -
{ -
printf( "%s: i = %dn", threadName.c_str(), i ); -
} -
} -
printf( "%s thread terminatingn", threadName.c_str() ); -
} - };
-
-
- int
main() - {
-
ThreadX * o1 = new ThreadX( 0, 1, 2000 ); -
-
HANDLE hth1; -
unsigned uiThread1ID; -
-
hth1 = (HANDLE)_beginthreadex( NULL, // security -
0, // stack size -
ThreadX::ThreadStaticEntryPoint, -
o1, // arg list -
CREATE_SUSPENDED, // so we can later call ResumeThread() -
&uiThread1ID ); -
-
if ( hth1 == 0 ) -
printf("Failed to create thread 1n"); -
-
DWORD dwExitCode; -
GetExitCodeThread( hth1, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259 -
printf( "initial thread 1 exit code = %un", dwExitCode ); -
-
o1->threadName = "t1"; -
-
ThreadX * o2 = new ThreadX( -100000, 0, 2000 ); -
-
HANDLE hth2; -
unsigned uiThread2ID; -
-
hth2 = (HANDLE)_beginthreadex( NULL, // security -
0, // stack size -
ThreadX::ThreadStaticEntryPoint, -
o2, // arg list -
CREATE_SUSPENDED, // so we can later call ResumeThread() -
&uiThread2ID ); -
-
if ( hth2 == 0 ) -
printf("Failed to create thread 2n"); -
-
GetExitCodeThread( hth2, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259 -
printf( "initial thread 2 exit code = %un", dwExitCode ); -
-
o2->threadName = "t2"; -
-
ResumeThread( hth1 ); // serves the purpose of Jaeschke's t1->Start() -
ResumeThread( hth2 ); -
-
WaitForSingleObject( hth1, INFINITE ); -
WaitForSingleObject( hth2, INFINITE ); -
-
GetExitCodeThread( hth1, &dwExitCode ); -
printf( "thread 1 exited with code %un", dwExitCode ); -
-
GetExitCodeThread( hth2, &dwExitCode ); -
printf( "thread 2 exited with code %un", dwExitCode ); -
-
CloseHandle( hth1 ); -
CloseHandle( hth2 ); -
-
delete o1; -
o1 = NULL; -
-
delete o2; -
o2 = NULL; -
-
printf("Primary thread terminating.n"); -
return 0; - }
二、解释
(1)如果你正在编写C/C++代码,决不应该调用CreateThread。相反,应该使用VisualC++运行期库函数_beginthreadex,退出也应该使用_endthreadex。如果不使用Microsoft的VisualC++编译器,你的编译器供应商有它自己的CreateThread替代函数。不管这个替代函数是什么,你都必须使用。
(2)因为_beginthreadex和_endthreadex是CRT线程函数,所以必须注意编译选项runtimelibaray的选择,使用MT或MTD。[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(),
BOOL GetThreadContext(HANDLE hThread,PCONTEXTpContext);
BOOL SwitchToThread();
三、注意
(1)C++主线程的终止,同时也会终止所有主线程创建的子线程,不管子线程有没有执行完毕。所以上面的代码中如果不调用WaitForSingleObject,则2个子线程t1和t2可能并没有执行完毕或根本没有执行。
(2)如果某线程挂起,然后有调用WaitForSingleObject等待该线程,就会导致死锁。所以上面的代码如果不调用resumethread,则会死锁。
四、为什么用_beginthreadex而不是CreateThread?
为什么要用C运行时库的_beginthreadex代替操作系统的CreateThread来创建线程?
来源自自1999年7月MSJ杂志的《Win32 Q&A》栏目
你也许会说我一直用CreateThread来创建线程,一直都工作得好好的,为什么要用_beginthreadex来代替CreateThread,下面让我来告诉你为什么。
回答一个问题可以有两种方式,一种是简单的,一种是复杂的。
如果你不愿意看下面的长篇大论,那我可以告诉你简单的答案:_beginthreadex在内部调用了CreateThread,在调用之前_beginthreadex做了很多的工作,从而使得它比CreateThread更安全。
最后
以上就是善良哈密瓜为你收集整理的windows下C语言多线程编程 一、需要的头文件支持 三、注意 四、为什么用_beginthreadex而不是CreateThread?的全部内容,希望文章能够帮你解决windows下C语言多线程编程 一、需要的头文件支持 三、注意 四、为什么用_beginthreadex而不是CreateThread?所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复