_beginThreadex创建多线程解读
_beginThreadex创建多线程解读
一、须要的头文件支持
#include <process.h> // for _beginthread()
须要的设置:ProjectàSetting-->C/C++-->User run-time library 选择Debug Multithreaded 或者Multithreaded。即使用: MT或MTD。
源代码例如以下:
#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;}static unsigned __stdcall ThreadStaticEntryPoint(void * pThis){ThreadX * pthX = (ThreadX*)pThis; // the tricky castpthX->ThreadEntryPoint(); // now call the true entry-point-functionreturn 1; // the thread exit code}void ThreadEntryPoint(){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()
{ThreadX * o1 = new ThreadX( 0, 1, 2000 );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 );o1->threadName = "t1";ThreadX * o2 = new ThreadX( -100000, 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";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 %u\n", dwExitCode );GetExitCodeThread( hth2, &dwExitCode );printf( "thread 2 exited with code %u\n", 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(), IDLE_PRIORITY_CLASS);
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更安全。
转载一部分,自己总结了一部分。
_beginThreadex创建多线程解读相关推荐
- _beginthreadex 创建多线程解读
一.解释 (1)如果你正在编写C/C++代码,决不应该调用CreateThread.相反,应该使用VisualC++运行期库函数_beginthreadex,退出也应该使用_endthreadex.如 ...
- C++多线程实例(_beginThreadex创建多线程)
C++多线程(二)(_beginThreadex创建多线程) C/C++ Runtime 多线程函数 一 简单实例(来自codeprojct:http://www.codeproject.com/us ...
- _beginthreadex创建多线程的用法
一.实例 #include <stdio.h> #include <string> // for STL string class #include <windows.h ...
- 采用_beginthread/_beginthreadex函数创建多线程
1.CRT简介: CRT: (C Runtime Library)即C运行时库,是系统运行的基础,包含了c常用的函数集(如:printf,malloc,strcpy等),为运行main做了初始化环境变 ...
- 转:MFC中创建多线程
MFC中创建多线程 MFC的多线程函数必须声明为静态的或者是全局函数(不同的在于全局函数不能访问类的私有静态成员,而静态类函数可以):但这样的线程函数只能访问静态的成员变量,要实现访问类的其他成员,可 ...
- java多线程w3c_Java创建多线程的三种方式
前言 这篇文章主要讲述线程的概念.组成.Java创建多线程的三种方式以及线程的类型. 线程概念 线程和进程的区别 **进程:**正在运行的程序,例如:你打开 的qq音乐.exe程序,其由PCB(进程控 ...
- python3创建多线程的几种方法
python3创建多线程主要有下面两种方法:函数.类 1.函数创建多线程 python3中,提供了一个内置模块threading.Thread,可以很方便的创建多线程,threading.Thread ...
- java 创建多线程_Java创建多线程
Java创建多线程 下一节> 到目前为止,我们仅用到两个线程:主线程和一个子线程.然而,你的程序可以创建所需的更多线程.例如,下面的程序创建了三个子线程: // Create multiple ...
- 多线程初探:三种方式创建多线程详细示例
多线程即在同一时间,可以做多件事情. 创建多线程有3种方式,分别是继承线程类,实现Runnable接口,匿名类 一:线程概念 首先要理解进程(Processor)和线程(Thread)的区别 进程:启 ...
最新文章
- 快速入门cocos2d-x jsbinding
- JBoss Modules – Module name
- jquery 总结
- centos6.8安装php7.3,CentOS7.6源码编译安装PHP 7.3.8
- COCI CONTEST #3 29.11.2014 KAMIONI
- php编写六十甲子纳音表_六十甲子纳音表详细说明,看看你属于什么命,属于那个颜色...
- (王道408考研操作系统)第一章计算机系统概述-第一节2:操作系统的发展史
- 基于FPGA实现压缩算法
- mysql分析函数的实现
- python基础代码大全-Python网络爬虫实战项目代码大全(长期更新,欢迎补充)
- 分享个短视频竞品分析报告
- mysql webmail ubuntu12.04 imap_如何在Ubuntu 18.04 LTS上安装最新的Roundcube Webmail
- Buildroot笔记
- 逃跑h5小游戏源码熊出没手机游戏
- 虚拟软盘启动OS方法
- 通用验证码识别SDK免费开源
- 【PPT】PPT设计丨1.实用功能丨
- 继承 封装 多态 (基础)描述性理解
- Jsdelivr CDN 加速服务又被 DNS 污染了(附临时解决方案)
- threeJS中4*4矩阵实现平移和旋转的原理
热门文章
- 父与子python下载不了_【求助】看父与子学习Python,里面有一个滑雪小游戏,加载不出图...
- 计算机专业课如何阅卷,全国计算机等级考试评卷老师是如何阅卷的?
- 使用BigDecimal时,报NumberFormatException
- 证书到期了_您的PMP证书到期了吗?
- 云主机安mysql_如何在云服务器 ECS 安装 MySQL
- c语言按照字节读取任何文件,【文件操作】【按字节读取】求鉴定问题……
- 计算机考研 东华大学,东华大学(专业学位)计算机技术考研难吗
- MyBatis foreach语句批量插入数据
- jenkins java jar_Jenkins 安装和配置、启动jar包
- 系统学习NLP(五)--句法分析