_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 cast
pthX->ThreadEntryPoint(); // now call the true entry-point-function
return ; // the thread exit code
} void ThreadEntryPoint()
{
for (int i = loopStart; i <= loopEnd; ++i)
{
if (i % dispFrequency == )
{
printf( "%s: i = %d\n", threadName.c_str(), i );
}
}
printf( "%s thread terminating\n", threadName.c_str() );
}
}; int main()
{
ThreadX * o1 = new ThreadX( , , ); HANDLE hth1;
unsigned uiThread1ID; hth1 = (HANDLE)_beginthreadex( NULL, // security
, // stack size
ThreadX::ThreadStaticEntryPoint,
o1, // arg list
CREATE_SUSPENDED, // so we can later call ResumeThread()
&uiThread1ID ); if ( hth1 == )
printf("Failed to create thread 1\n"); DWORD dwExitCode;
GetExitCodeThread( hth1, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259
printf( "initial thread 1 exit code = %u\n", dwExitCode ); o1->threadName = "t1"; ThreadX * o2 = new ThreadX( -, , ); HANDLE hth2;
unsigned uiThread2ID; hth2 = (HANDLE)_beginthreadex( NULL, // security
, // stack size
ThreadX::ThreadStaticEntryPoint,
o2, // arg list
CREATE_SUSPENDED, // so we can later call ResumeThread()
&uiThread2ID ); if ( hth2 == )
printf("Failed to create thread 2\n"); GetExitCodeThread( hth2, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259
printf( "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 ;
}

二、解释

(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更安全

转载一部分,自己总结了一部分。

出处:http://blog.csdn.net/laoyang360/article/details/7720656

使用_beginThreadex创建多线程(C语言版多线程)的更多相关文章

  1. _beginThreadex创建多线程解读【转】

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

  2. _beginThreadex创建多线程解读

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

  3. c语言下多线程

    原文:c语言下多线程 [问题]创建了10个线程,10个线程公用一个线程体,创建如下: int t1=0,t2=1,t3=2,t4=3,t5=4,t6=5,t7=6,t8=7,t9=8,t10=9; i ...

  4. [R语言]R语言使用多线程对数据库进行大批量访问时出现无法连接问题

    问题描述: 在R中使用多线程对数据库进行写入,在服务器端运行脚本(linux环境),总是在第6-7万个任务线程时,出现无法连接到数据库的问题.任务中断,错误信息为task 6xxxx failed,C ...

  5. swift语言之多线程操作和操作队列(下)———坚持51天吃掉大象(写技术文章)

    欢迎有兴趣的朋友,参与我的美女同事发起的活动<51天吃掉大象>,该美女真的很疯狂,希望和大家一起坚持51天做一件事情,我加入这个队伍,希望坚持51天每天写一篇技术文章.关注她的微信公众号: ...

  6. 基于JAVA语言的多线程技术

    1.简介 多线程技术属于操作系统范围内的知识: 进程与线程 可以这么理解,一个应用程序就是一个进程,在一个进程中包含至少一个线程:进程就是线程的容器,真正工作.处理任务的是线程. 进程是操作系统分配资 ...

  7. 趣谈多线程(Python版)

    温馨提示:本文篇幅较长,建议读者耐心阅读,本文中的代码经过笔者精心构思,可以复制过去运行一下,观察输出结果,所有代码在python3.5.0中测试通过. 文章目录 What is 多线程? Why w ...

  8. 多线程学习:win32多线程编程基本概念(转)

    一.定义: 1.进程和线程的区别 进程:是程序的执行过程,具有动态性,即运行的程序就叫进程,不运行就叫程序 ,每个进程包含一到多个线程.线程:系统中的最小执行单元,同一进程中有多个线程,线程可以共享资 ...

  9. Windows 8.1 with Update 镜像下载(增OEM单语言版)

    该系统已有更新的版本,请转至<Windows 8.1 with update 官方最新镜像汇总>下载. 2014年4月9日凌晨,微软向MSDN订阅用户开放了Windows 8.1 with ...

随机推荐

  1. 20154312曾林 - Exp1 PC平台逆向破解

    1.逆向及Bof基础实践说明 1.1-实践目标 对象:pwn1(linux可执行文件) 目标:使程序执行另一个代码片段:getshell 内容: 手工修改可执行文件,改变程序执行流程,直接跳转到get ...

  2. 《Java入门第二季》第一章 类和对象

    什么是类和对象 如何定义 Java 中的类 如何使用 Java 中的对象 Java中的成员变量和局部变量1.成员变量:在类中定义,描述构成对象的组件. 2.局部变量:在类的方法中,用于临时保存数据. ...

  3. Apache HttpClient4使用教程

    基于HttpClient 4.5.2 执行GET请求 CloseableHttpClient httpClient = HttpClients.custom() .build(); Closeable ...

  4. 20145326 《Java程序设计》第6周学习总结

    20145326 <Java程序设计>第6周学习总结 教材学习内容总结 第十章 一.使用InputStream与OutputStream 1.串流设计的概念 想活用输入/输出API,一定要 ...

  5. CF_863_F(Netflow)

    codeforces_863_F 题目大意:给出一个数组的大小(n<=50),以及每个位置填数的范围限制(若无限制,即为1-n),最后求填出数组的最小花费,定义总花费为数组中每个数出现次数的平方 ...

  6. CSU 1968 Permutation Descent Counts

    http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1968 题意:对于任一种N的排列A,定义它的E值为序列中满足A[i]>A[i+1]的数的个 ...

  7. tp5.1 Env使用

    5.1版本取消了所有的系统常量,原来的系统路径变量改为使用Env类获取(需要引入think\facade\Env) echo "app_path=========".Env::ge ...

  8. SSH防止暴力破解--fail2ban

    一.ssh密钥对无交互登录 实战1:通过密钥进行sshd服务认证 服务端:linl_S    IP:10.0.0.15 客户端:lin_C    IP:10.0.0.16   1)在客户端生成密钥对 ...

  9. session放数据库里解决丢失的问题

    在编程里是会话的意思Session 对象存储特定用户会话所需的信息.这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去. ...

  10. Django框架基于session的登录/注销实现

    博主最近想基于Django框架开发一个测试平台,第一版先实现查看下载自动化的测试报告文件 第一步:前端框架 网上选择一款开源boostrap的前端框架 AdminLTE,这里给个链接  https:/ ...