热门标签 | 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;如果不用这个会有内存泄漏。



推荐阅读
  • 本文探讨了如何通过预处理器开关选择不同的类实现,并解决在特定情况下遇到的链接器错误。 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 本文详细介绍了一种通过MySQL弱口令漏洞在Windows操作系统上获取SYSTEM权限的方法。该方法涉及使用自定义UDF DLL文件来执行任意命令,从而实现对远程服务器的完全控制。 ... [详细]
  • 版本控制工具——Git常用操作(下)
    本文由云+社区发表作者:工程师小熊摘要:上一集我们一起入门学习了git的基本概念和git常用的操作,包括提交和同步代码、使用分支、出现代码冲突的解决办法、紧急保存现场和恢复 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 使用PHP实现网站访客计数器的完整指南
    本文详细介绍了如何利用PHP构建一个简易的网站访客统计系统。通过具体的代码示例和详细的解释,帮助开发者理解和实现这一功能,适用于初学者和有一定经验的开发人员。 ... [详细]
  • 探讨 HDU 1536 题目,即 S-Nim 游戏的博弈策略。通过 SG 函数分析游戏胜负的关键,并介绍如何编程实现解决方案。 ... [详细]
  • 在尝试使用C# Windows Forms客户端通过SignalR连接到ASP.NET服务器时,遇到了内部服务器错误(500)。本文将详细探讨问题的原因及解决方案。 ... [详细]
  • 深入解析动态代理模式:23种设计模式之三
    在设计模式中,动态代理模式是应用最为广泛的一种代理模式。它允许我们在运行时动态创建代理对象,并在调用方法时进行增强处理。本文将详细介绍动态代理的实现机制及其应用场景。 ... [详细]
  • Symfony是一个功能强大的PHP框架,以其依赖注入(DI)特性著称。许多流行的PHP框架如Drupal和Laravel的核心组件都基于Symfony构建。本文将详细介绍Symfony的安装方法及其基本使用。 ... [详细]
  • 由二叉树到贪心算法
    二叉树很重要树是数据结构中的重中之重,尤其以各类二叉树为学习的难点。单就面试而言,在 ... [详细]
  • JavaScript中的数组是数据集合的核心结构之一,内置了多种实用的方法。掌握这些方法不仅能提高开发效率,还能显著提升代码的质量和可读性。本文将详细介绍数组的创建方式及常见操作方法。 ... [详细]
  • 在编译BSP包过程中,遇到了一个与 'gets' 函数相关的编译错误。该问题通常发生在较新的编译环境中,由于 'gets' 函数已被弃用并视为安全漏洞。本文将详细介绍如何通过修改源代码和配置文件来解决这一问题。 ... [详细]
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社区 版权所有