使用_beginThreadex创建多线程(C语言版多线程)

使用_beginThreadex创建多线程(C语言版多线程)_beginThreadex创建多线程解读一、需要的头文件支持#include//for_beginthread()需要的设置:ProjectàSetting–>C/C++–

大家好,又见面了,我是你们的朋友全栈君。

_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 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, // security  0, // stack size   ThreadX::ThreadStaticEntryPoint, o1, // arg list  CREATE_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 = 259  printf( "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, // security  0, // stack size   ThreadX::ThreadStaticEntryPoint, o2, // arg list  CREATE_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 = 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 0; } 

 

二、解释

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

(2)因为_beginthreadex和_endthreadex是CRT线程函数,所以必须注意编译选项runtimelibaray的选择,使用MTMTD。[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来创建线程?

来源自自19997MSJ杂志的《Win32 Q&A》栏目

你也许会说我一直用CreateThread来创建线程,一直都工作得好好的,为什么要用_beginthreadex来代替CreateThread,下面让我来告诉你为什么。

回答一个问题可以有两种方式,一种是简单的,一种是复杂的。

如果你不愿意看下面的长篇大论,那我可以告诉你简单的答案:_beginthreadex在内部调用了CreateThread,在调用之前_beginthreadex做了很多的工作,从而使得它比CreateThread更安全

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/155711.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • OpenWrite 博客群发使用步骤[通俗易懂]

    OpenWrite 博客群发使用步骤[通俗易懂]OpenWrite,做最懂自媒体的工具平台。主要是群发软件、博客导流公众号阅读全文工具媒体发布平台、博客群发平台、软文推广平台软文推广发布、博客发布官网引流科技小工具微信公众号Markdown编辑器、多平台免费图床配置Markdown编辑器的免费简洁流畅、文章一键群发等的免费自媒体运营工具助手注意:当前版本必须使用Chrome浏览器,并安装插件「OpenWrite助手」https://openwrite.cn/plugin-chrome/1、点击指定渠道图标,在新窗口登录渠道的账号

  • ssl原理及应用_ssl的理解

    ssl原理及应用_ssl的理解今天学习网络通信,看到使用ssl(SecureSocketsLayer)进行加密,由于对ssl只是有些概念上的了解,对于具体应用原理、过程和如何使用不慎了解,于是学习了一番,总结如下:1.为什么要使用ssl?确保数据传输的安全性2.用ssl加密传输的实际过程?建立连接时使用非对称加密,而连接完成后在传输数据时使用对称加密(速度快)3.ssl加密方式?有两种方式:单

    2022年10月31日
  • oidc auth2.0_使用Spring Security 5.0和OIDC轻松构建身份验证「建议收藏」

    oidc auth2.0_使用Spring Security 5.0和OIDC轻松构建身份验证「建议收藏」oidcauth2.0“我喜欢编写身份验证和授权代码。”〜从来没有Java开发人员。厌倦了一次又一次地建立相同的登录屏幕?尝试使用OktaAPI进行托管身份验证,授权和多因素身份验证。SpringSecurity不仅是一个功能强大且可高度自定义的身份验证和访问控制框架,它还是保护基于Spring的应用程序的实际标准。从前,SpringSecurity需要使用大量的XML来…

  • outputstream类或writer类的子类_java private

    outputstream类或writer类的子类_java privateJavaOutputStreamWriter类在本教程中,我们将借助示例学习JavaOutputStreamWriter及其方法。java.io包的OutputStreamWriter类可用于将字符形式的数据转换为字节形式的数据。它继承了抽象类Writer。OutputStreamWriter类可与其他输出流一起使用。它也被称为字节流和字符流之间的桥梁。这是因为OutputStreamW…

  • BigDecimal 类型比较大小

    BigDecimal 类型比较大小1.标准做法Longzero=0l;BigDecimalbig_decimal_num=newBigDecimal(zero);intr=big_decimal_num.compareTo(BigDecimal.ZERO);//和0,Zero比较if(r==0)//等于…

  • C++使用curl发送post请求

    C++使用curl发送post请求发送post请求代码如下:#include<iostream>#include<string>#include<curl\curl.h>usingnamespacestd;//get请求和post请求数据响应函数size_treq_reply(void*ptr,size_tsize,size_tnmemb,void*stream)…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号