一、实例


#include <stdio.h>
#include <string>             // for STL string class
#include <windows.h>          // for HANDLE
#include <process.h>          // 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;}// In C++ you must employ a free (C) function or a static// class member function as the thread entry-point-function.// Furthermore, _beginthreadex() demands that the thread// entry function signature take a single (void*) and returned// an unsigned.static unsigned __stdcall ThreadStaticEntryPoint(void * pThis){ThreadX * pthX = (ThreadX*)pThis;   // the tricky castpthX->ThreadEntryPoint();           // now call the true entry-point-function// A thread terminates automatically if it completes execution,// or it can terminate itself with a call to _endthread().return 1;          // the thread exit code}void ThreadEntryPoint(){// This is the desired entry-point-function but to get// here we have to use a 2 step procedure involving// the ThreadStaticEntryPoint() function.for (int i = loopStart; i <= loopEnd; ++i){if (i % dispFrequency == 0){printf( "%s: i = %d\n", threadName.c_str(), i );}}printf( "%s thread terminating\n", threadName.c_str() );}
};int main()
{// All processes get a primary thread automatically. This primary// thread can generate additional threads.  In this program the// primary thread creates 2 additional threads and all 3 threads// then run simultaneously without any synchronization.  No data// is shared between the threads.// We instantiate an object of the ThreadX class. Next we will// create a thread and specify that the thread is to begin executing// the function ThreadEntryPoint() on object o1. Once started,// this thread will execute until that function terminates or// until the overall process terminates.ThreadX * o1 = new ThreadX( 0, 1, 2000 );// When developing a multithreaded WIN32-based application with// Visual C++, you need to use the CRT thread functions to create// any threads that call CRT functions. Hence to create and terminate// threads, use _beginthreadex() and _endthreadex() instead of// the Win32 APIs CreateThread() and EndThread().// The multithread library LIBCMT.LIB includes the _beginthread()// and _endthread() functions. The _beginthread() function performs// initialization without which many C run-time functions will fail.// You must use _beginthread() instead of CreateThread() in C programs// built with LIBCMT.LIB if you intend to call C run-time functions.// Unlike the thread handle returned by _beginthread(), the thread handle// returned by _beginthreadex() can be used with the synchronization APIs.HANDLE   hth1;unsigned  uiThread1ID;hth1 = (HANDLE)_beginthreadex( NULL,         // security0,            // stack sizeThreadX::ThreadStaticEntryPoint,o1,           // arg listCREATE_SUSPENDED,  // so we can later call ResumeThread()&uiThread1ID );if ( hth1 == 0 )printf("Failed to create thread 1\n");DWORD   dwExitCode;GetExitCodeThread( hth1, &dwExitCode );  // should be STILL_ACTIVE = 0x00000103 = 259printf( "initial thread 1 exit code = %u\n", dwExitCode );// The System::Threading::Thread object in C++/CLI has a "Name" property.// To create the equivalent functionality in C++ I added a public data member// named threadName.o1->threadName = "t1";ThreadX * o2 = new ThreadX( -1000000, 0, 2000 );HANDLE   hth2;unsigned  uiThread2ID;hth2 = (HANDLE)_beginthreadex( NULL,         // security0,            // stack sizeThreadX::ThreadStaticEntryPoint,o2,           // arg listCREATE_SUSPENDED,  // so we can later call ResumeThread()&uiThread2ID );if ( hth2 == 0 )printf("Failed to create thread 2\n");GetExitCodeThread( hth2, &dwExitCode );  // should be STILL_ACTIVE = 0x00000103 = 259printf( "initial thread 2 exit code = %u\n", dwExitCode );o2->threadName = "t2";// If we hadn't specified CREATE_SUSPENDED in the call to _beginthreadex()// we wouldn't now need to call ResumeThread().ResumeThread( hth1 );   // serves the purpose of Jaeschke's t1->Start()ResumeThread( hth2 );// In C++/CLI the process continues until the last thread exits.// That is, the thread's have independent lifetimes. Hence// Jaeschke's original code was designed to show that the primary// thread could exit and not influence the other threads.// However in C++ the process terminates when the primary thread exits// and when the process terminates all its threads are then terminated.// Hence if you comment out the following waits, the non-primary// threads will never get a chance to run.WaitForSingleObject( hth1, INFINITE );WaitForSingleObject( hth2, INFINITE );GetExitCodeThread( hth1, &dwExitCode );printf( "thread 1 exited with code %u\n", dwExitCode );GetExitCodeThread( hth2, &dwExitCode );printf( "thread 2 exited with code %u\n", dwExitCode );// The handle returned by _beginthreadex() has to be closed// by the caller of _beginthreadex().CloseHandle( hth1 );CloseHandle( hth2 );delete o1;o1 = NULL;delete o2;o2 = NULL;printf("Primary thread terminating.\n");
}

二、解释


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

2.因为_beginthreadex和_endthreadex是CRT线程函数,所以必须注意编译选项runtimelibaray的选择,使用MT或MTD。

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

  • 每个线程均获得由C/C++运行期库的堆栈分配的自己的tiddata内存结构。(tiddata结构位于Mtdll.h文件中的VisualC++源代码中)。
  • 传递给_beginthreadex的线程函数的地址保存在tiddata内存块中。传递给该函数的参数也保存在该数据块中。
  • _beginthreadex确实从内部调用CreateThread,因为这是操作系统了解如何创建新线程的唯一方法。
  • 当调用CreatetThread时,它被告知通过调用_threadstartex而不是pfnStartAddr来启动执行新线程。还有,传递给线程函数的参数是tiddata结构而不是pvParam的地址。
  • 如果一切顺利,就会像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,DWORD dwIdealProcessor);
  • BOOL SetThreadPriority(HANDLE hThread,int nPriority);
  • BOOL SetPriorityClass(GetCurrentProcess(),  IDLE_PRIORITY_CLASS);
  • BOOL GetThreadContext(HANDLE hThread,PCONTEXT pContext);
  • BOOL SwitchToThread();

三、注意


  1. C++主线程的终止,同时也会终止所有主线程创建的子线程,不管子线程有没有执行完毕。所以上面的代码中如果不调用WaitForSingleObject,则2个子线程t1和t2可能并没有执行完毕或根本没有执行。
  2. 如果某线程挂起,然后有调用WaitForSingleObject等待该线程,就会导致死锁。所以上面的代码如果不调用ResumeThread,则会死锁。

_beginthreadex创建多线程的用法相关推荐

  1. C++多线程实例(_beginThreadex创建多线程)

    C++多线程(二)(_beginThreadex创建多线程) C/C++ Runtime 多线程函数 一 简单实例(来自codeprojct:http://www.codeproject.com/us ...

  2. _beginThreadex创建多线程解读

    _beginThreadex创建多线程解读 一.须要的头文件支持 #include <process.h>         // for _beginthread() 须要的设置:Proj ...

  3. _beginthreadex 创建多线程解读

    一.解释 (1)如果你正在编写C/C++代码,决不应该调用CreateThread.相反,应该使用VisualC++运行期库函数_beginthreadex,退出也应该使用_endthreadex.如 ...

  4. 采用_beginthread/_beginthreadex函数创建多线程

    1.CRT简介: CRT: (C Runtime Library)即C运行时库,是系统运行的基础,包含了c常用的函数集(如:printf,malloc,strcpy等),为运行main做了初始化环境变 ...

  5. Python爬虫进阶五之多线程的用法

    前言 我们之前写的爬虫都是单个线程的?这怎么够?一旦一个地方卡到不动了,那不就永远等待下去了?为此我们可以使用多线程或者多进程来处理. 首先声明一点! 多线程和多进程是不一样的!一个是 thread ...

  6. 转:MFC中创建多线程

    MFC中创建多线程 MFC的多线程函数必须声明为静态的或者是全局函数(不同的在于全局函数不能访问类的私有静态成员,而静态类函数可以):但这样的线程函数只能访问静态的成员变量,要实现访问类的其他成员,可 ...

  7. Qt创建多线程的两种方法

    来源:https://github.com/czyt1988/czyBlog/tree/master/tech/QtThread 1.摘要 Qt有两种多线程的方法,其中一种是继承QThread的run ...

  8. java多线程w3c_Java创建多线程的三种方式

    前言 这篇文章主要讲述线程的概念.组成.Java创建多线程的三种方式以及线程的类型. 线程概念 线程和进程的区别 **进程:**正在运行的程序,例如:你打开 的qq音乐.exe程序,其由PCB(进程控 ...

  9. python3创建多线程的几种方法

    python3创建多线程主要有下面两种方法:函数.类 1.函数创建多线程 python3中,提供了一个内置模块threading.Thread,可以很方便的创建多线程,threading.Thread ...

最新文章

  1. NSWindow添加NSViewController
  2. Codeforces Round #Pi (Div. 2) D. One-Dimensional Battle Ships set区间分解
  3. Linux下巧妙使用邮件服务器之postfix(认证+web)
  4. 从一个小demo开始,体验“API经济”的大魅力
  5. K-means的缺点(优化不仅仅是最小化误差)
  6. JSTL之数字、日期格式化fmt:formatNumber/、fmt:formatDate/
  7. python封装模块_Python练手,封装日志模块,v2
  8. 3-29Pytorch与autograd梯度与机器学习
  9. linux的ky3关闭防火墙,ky3-8
  10. 解决IIS7.5及以后中URL文件名有加号或空格导致显示404错误的问题
  11. 【matlab】syms x y 用法
  12. 微软使用“钞能力”: 687 亿美元收购动视暴雪!
  13. Android 9 禁用按住电源键+音量加键进入工厂测试(recovery模式)功能
  14. 东北大学计算机考研专业842包括什么,东北大学2019年计算机考研842计算机专业基础考试大纲...
  15. 我账户不显示pop3服务器地址,Hotmail 邮箱POP3服务器的设置方法
  16. [面试题] 从抽屉找东西的概率学问题
  17. 电脑连不上网,WiFi没有显示出来
  18. 四十七、使用bootstrap中的选项卡制作产品特色页面
  19. 结对编程项目-四则运算整体总结
  20. 八、新人成才之路《成才大原则 你不成才是学习方法错了》

热门文章

  1. PS图像如何转换为位图模式?
  2. C++ aop设计模式,动态横切的实现
  3. vue+django智能点餐系统
  4. 解密阿里数据库女程序员梓仪、璇戈、依诺代码诗!
  5. python与php哪个有前景_python和php哪个更有前景
  6. DEDECMS5.7 用星星图标表示软件等级
  7. javascript的堆栈原理
  8. JMeter 5.4下载、安装、使用教程
  9. H5跳转小程序,小程序跳转小程序
  10. 咸鱼Maya笔记—创建快照动画