热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用_beginthreadex()创建线程

前面一直讲到使用CreateThread来创建线程,那么这章告诉你应该使用_beginthreadex()取代CreateThread()。一、使用_beginthr
前面一直讲到使用CreateThread来创建线程,那么这章告诉你应该使用_beginthreadex()取代CreateThread()。




一、使用_beginthreadex()             

       需要的头文件支持#include         // for _beginthread()
      需要的设置: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 &#61; startValue;loopEnd &#61; endValue;dispFrequency &#61; frequency;}static unsigned __stdcall ThreadStaticEntryPoint(void * pThis){ThreadX * pthX &#61; (ThreadX*)pThis; // the tricky castpthX->ThreadEntryPoint(); // now call the true entry-point-functionreturn 1; // the thread exit code}void ThreadEntryPoint(){for (int i &#61; loopStart; i <&#61; loopEnd; &#43;&#43;i){if (i % dispFrequency &#61;&#61; 0){printf( "%s: i &#61; %d\n", threadName.c_str(), i );}}printf( "%s thread terminating\n", threadName.c_str() );}
};int main()
{ThreadX * o1 &#61; new ThreadX( 0, 1, 2000 );HANDLE hth1;unsigned uiThread1ID;hth1 &#61; (HANDLE)_beginthreadex( NULL, // security0, // stack sizeThreadX::ThreadStaticEntryPoint,o1, // arg listCREATE_SUSPENDED, // so we can later call ResumeThread()&uiThread1ID );if ( hth1 &#61;&#61; 0 )printf("Failed to create thread 1\n");DWORD dwExitCode;GetExitCodeThread( hth1, &dwExitCode ); // should be STILL_ACTIVE &#61; 0x00000103 &#61; 259printf( "initial thread 1 exit code &#61; %u\n", dwExitCode );o1->threadName &#61; "t1";ThreadX * o2 &#61; new ThreadX( -100000, 0, 2000 );HANDLE hth2;unsigned uiThread2ID;hth2 &#61; (HANDLE)_beginthreadex( NULL, // security0, // stack sizeThreadX::ThreadStaticEntryPoint,o2, // arg listCREATE_SUSPENDED, // so we can later call ResumeThread()&uiThread2ID );if ( hth2 &#61;&#61; 0 )printf("Failed to create thread 2\n");GetExitCodeThread( hth2, &dwExitCode ); // should be STILL_ACTIVE &#61; 0x00000103 &#61; 259printf( "initial thread 2 exit code &#61; %u\n", dwExitCode );o2->threadName &#61; "t2";ResumeThread( hth1 ); // serves the purpose of Jaeschke&#39;s t1->Start()ResumeThread( hth2 ); 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 );CloseHandle( hth1 );CloseHandle( hth2 );delete o1;o1 &#61; NULL;delete o2;o2 &#61; NULL;printf("Primary thread terminating.\n");return 0;
}

注意&#xff1a;
&#xff08;1&#xff09;如果你正在编写C/C&#43;&#43;代码&#xff0c;决不应该调用CreateThread。相反&#xff0c;应该使用VisualC&#43;&#43;运行期库函数_beginthreadex&#xff0c;退出也应该使用_endthreadex。如果不使用Microsoft的VisualC&#43;&#43;编译器&#xff0c;你的编译器供应商有它自己的CreateThread替代函数。不管这个替代函数是什么&#xff0c;你都必须使用。

&#xff08;2&#xff09;因为_beginthreadex和_endthreadex是CRT线程函数&#xff0c;所以必须注意编译选项runtimelibaray的选择&#xff0c;使用MT或MTD。[MultiThreaded , Debug MultiThreaded]。
&#xff08;3&#xff09;_beginthreadex函数的参数列表与CreateThread函数的参数列表是相同的&#xff0c;但是参数名和类型并不完全相同。这是因为Microsoft的C/C&#43;&#43;运行期库的开发小组认为&#xff0c;C/C&#43;&#43;运行期函数不应该对Windows数据类型有任何依赖。_beginthreadex函数也像CreateThread那样&#xff0c;返回新创建的线程的句柄。
&#xff08;4&#xff09;C&#43;&#43;主线程的终止&#xff0c;同时也会终止所有主线程创建的子线程&#xff0c;不管子线程有没有执行完毕。所以上面的代码中如果不调用WaitForSingleObject&#xff0c;则2个子线程t1和t2可能并没有执行完毕或根本没有执行。
&#xff08;5&#xff09;如果某线程挂起&#xff0c;然后有调用WaitForSingleObject等待该线程&#xff0c;就会导致死锁。所以上面的代码如果不调用resumethread&#xff0c;则会死锁。






二、区别                                   

CreateThread是Windows的API函数(SDK函数的标准形式,直截了当的创建方式&#xff0c;任何场合都可以使用)&#xff0c;提供操作系统级别的创建线程的操作&#xff0c;且仅限于工作者线程。不调用MFC和RTL的函数时&#xff0c;可以用CreateThread&#xff0c;其它情况不要轻易。在使用的过程中要考虑到进程的同步与互斥的关系&#xff08;防止死锁&#xff09;。线程函数定义为&#xff1a;DWORD WINAPI _yourThreadFun(LPVOID pParameter)。但它没有考虑&#xff1a;
&#xff08;1&#xff09;C Runtime中需要对多线程进行纪录和初始化&#xff0c;以保证C函数库工作正常&#xff08;典型的例子是strtok函数&#xff09;。
&#xff08;2&#xff09;MFC也需要知道新线程的创建&#xff0c;也需要做一些初始化工作&#xff08;当然&#xff0c;如果没用MFC就没事了&#xff09;。   

AfxBeginThread&#xff1a;MFC中线程创建的MFC函数&#xff0c;首先创建了相应的CWinThread对象&#xff0c;然后调用CWinThread::CreateThread,   在CWinThread::CreateThread中&#xff0c;完成了对线程对象的初始化工作&#xff0c;然后&#xff0c;调用_beginthreadex(AfxBeginThread相比较更为安全)创建线程。它简化了操作或让线程能够响应消息&#xff0c;即可用于界面线程&#xff0c;也可以用于工作者线程&#xff0c;但要注意不要在一个MFC程序中使用_beginthreadex()或CreateThread()。线程函数定义为&#xff1a;UINT _yourThreadFun(LPVOID pParam)

_beginthreadex&#xff1a;MS对C Runtime库的扩展SDK函数&#xff0c;首先针对C Runtime库做了一些初始化的工作&#xff0c;以保证C Runtime库工作正常。然后&#xff0c;调用CreateThread真正创建线程。 仅使用Runtime Library时&#xff0c;可以用_BegingThread。

小节&#xff1a;实际上&#xff0c;这三个函数之间存在一定的调用关系&#xff0c;第一个纯粹一些&#xff0c;后两个完成自己相应的工作之后&#xff0c;调用前者实现线程的创建。其中CreateThread是由操作系统提供的接口&#xff0c;而AfxBeginThread和_BeginThread则是编译器对它的封装。
小节&#xff1a;用_beginthreadex()、_endthreadex函数应该是最佳选择&#xff0c;且都是C Run-time Library中的函数&#xff0c;函数的参数和数据类型都是C Run-time Library中的类型&#xff0c;这样在启动线程时就不需要进行Windows数据类型和C Run-time Library中的数据类型之间的转化&#xff0c;从而&#xff0c;减低了线程启动时的资源消耗和时间的消耗。但使用_beginthread&#xff0c;无法创建带有安全属性的新线程&#xff0c;无法创建暂停的线程&#xff0c;也无法获得 线程ID&#xff0c;_endthread的情况类似&#xff0c;它不带参数&#xff0c;这意味这线程的退出代码必须硬编码为0。
小节&#xff1a;MFC也是C&#43;&#43;类库&#xff08;只不过是Microsoft的C&#43;&#43;类库&#xff0c;不是标准的C&#43;&#43;类库&#xff09;&#xff0c;在MFC中也封装了new和delete两中运算符&#xff0c;所以用到new和delete的地方不一定非要使用_beginthreadex() 函数&#xff0c;用其他两个函数都可以。

_beginthreadex和_beginthread在回调入口函数之前进行一些线程相关的CRT的初始化操作。
CRT的函数库在线程出现之前就已经存在&#xff0c;所以原有的CRT不能真正支持线程&#xff0c;
这也导致了许多CRT的函数在多线程的情况下必须有特殊的支持&#xff0c;不能简单的使用CreateThread就OK。
补充一点&#xff0c;_beginthreadex()是针对CRT的线程函数&#xff0c;在线程中若要用到CRT的函数&#xff0c;最好用这个启动线程&#xff0c;如果不用这个会有内存泄漏。



推荐阅读
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了源码分析--ConcurrentHashMap与HashTable(JDK1.8)相关的知识,希望对你有一定的参考价值。  Concu ... [详细]
  • NN,NearestNeighbor,最近邻KNN,K-NearestNeighbor,K最近邻KNN分类的思路:分类的过程其实是直接将测试集的每一个图片和训练集中的所有图片进行比 ... [详细]
  • 路径查找基础知识-动画演示
    这是教程教你建立路径查找算法的第一步。路径查找就是在两点之间查找最短路径的算法,你可以在很多地方应用,例如:玩家控制角色时通过点击设置目的地时,就需要用到。在开始前,我们需要明确一点:路径查找是在终点 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 似乎有两种不同的方法可以将字符串转换为字节,如对typeerror的回答所示:str不支持缓冲区接口。这些方法中哪一种比较好或更适合用Python& ... [详细]
author-avatar
佳鈺佳琴欣怡
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有