- 浏览: 3417292 次
- 性别:
- 来自: 苏州
文章分类
最新评论
-
sonichy:
Qt5改动很多,要改改了。
基于QItemDelegate的例子1 SpinBoxDelegate -
我的主页6:
楼主,2.2子查询的分页方式:SELECT * FROM ar ...
Mysql 分页语句Limit用法 -
liguoqi:
非常感谢楼主的用心指导,工具以及图片例子都提供了 赞!
两款免费DCIOM 图像浏览软件介绍和DICOM图像例子供下载 -
liguoqi:
问下这个图片怎么解压损坏呀
两款免费DCIOM 图像浏览软件介绍和DICOM图像例子供下载 -
liguoqi:
楼主讲解的非常详细,还附带工具和图片例子,非常感谢
两款免费DCIOM 图像浏览软件介绍和DICOM图像例子供下载
_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的选择,使用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更安全。
转载一部分,自己总结了一部分。
发表评论
-
C++ 实现把非静态成员函数作为回调函数(非static)
2012-11-16 10:10 14431众所周知,C++的类成员函数不能像普通函数那样用于回调,因 ... -
【转】windows多线程CreateThread与_beginthreadex本质区别
2012-11-15 14:40 13755本文将带领你与多线程作第一次亲密接触,并深入分析Crea ... -
ostringstream 的清空数据方法
2012-09-27 15:28 19269关于C++中 <sstream>中ostrings ... -
输入参数和输出参数
2012-09-26 10:43 36041. 输入参数,是函数的调用者,传递给函数的实现者,对函 ... -
ofstream、ifstream、fstream
2012-09-23 19:23 2843学习一下C++的文件流: ofstream是从内 ... -
将ostream 对象转换成字符串流输出
2012-09-22 10:47 8531将ostream 对象转换成字符串流输出 因为项目中需 ... -
sstream和strstream以及fstream
2012-09-22 10:38 4355在C++有两种字符串流,也称为数组I/O流,一种在sstre ... -
字符串流 ostrstream 和 istrstream
2012-09-22 10:28 7859ostrstream类流 /*ostrst ... -
将有格式的int解析成float
2012-09-20 18:10 2218因项目中有一个需求:将采集到所有short int 转换成fl ... -
回调函数测试例子
2012-09-29 14:15 4250回调函数就是一个通过函数指针调用的函数。如果你把函数的指 ... -
fatal error C1083: Cannot open include file: 'iostream.h': No such file or dire
2012-09-20 17:19 6337错误: fatal error C1083: Cannot o ... -
C++中类的声明
2012-08-29 16:28 6893可以声明一个类而不定义它 class Sc ... -
only static const integral data members can be initialized within a class
2012-06-28 11:40 2686翻译一下:只有静态整型常量数据成员能在类中初始化 ... -
fstream与 C 风格(例如fread 和 fwrite )两种读写文件方法的效率比较
2012-06-27 17:21 20838我觉得作者写的挺好,评论也写的很对。 目前我的项目 ... -
C/C++快速写入类结构对象进入文件
2012-06-19 10:38 0void QObject::deleteLater() { ... -
C语言文件操作函数大全
2012-06-18 13:54 2306C语言文件操作函数大 ... -
C++ 动态申请数组
2012-06-09 00:05 6653方法1、C++使用vector方便 ... -
VC++动态链接库(DLL)编程深入浅出(ZZ)
2012-06-08 10:06 23851.概论 先来阐述一下DLL(Dynamic Link ... -
C++中的头文件和源文件
2012-05-09 14:54 6556一、C++编译模式 通常 ... -
C语言下,获取文件信息
2012-05-08 15:07 6628C语言下,如何获取文件的生成时间,日期和文件大小等文件信息。 ...
相关推荐
windows环境下C语言多线程实现网络编程,多人聊天室,[总结].pdf
自己编的基于UDP的socket程序,收发一体,支持多线程操作
c语言多进程多线程编程c语言多进程多线程编程c语言多进程多线程编程c语言多进程多线程编程
【个人总结系列-48】Windows及Linux环境下的C语言多线程编程总结.docx
windows环境下C语言多线程实现网络编程,多人聊天室,.pdf
统中才引入多线程机制,如今,由于自身的许多优点,多线程编程已经得到了广泛的应用。 本文我们将介绍在Linux 下编写多进程和多线程程序的一些初步知识。 1 引言 对于没有接触过 Unix/Linux 操作系统的人来说,fork ...
windows环境下C语言多线程实现网络编程,多人聊天室,[收集].pdf
本书通过众多实例介绍了如何实现Windows下的多线程编程,既重点介绍了Win32API下的多线程编程和MFC下的多线程编程,又介绍了多线程机制在网络编程、图形编程和数据库中的应用。本书每一章都从简单的多线程实例出发...
Linux下C语言应用编程》深入浅出地讲解了Linux下C应用程序开发所需的基本工具、知识和技巧,主要包括:开发工具的使用和技巧、文件I/O编程、多进程编程、进程间通信、多线程编程、网络编程等内容。可以让读者轻松、...
此实例在windows 10系统上可以成功运行,可以修改一下,在linux上也可以运行,思路都是一样的。 说明:这个是个图书馆案例,默认100个座位,生产者与消费者各2个线程 (修改:加锁)
本书范例丰富,且具有代表性,如Socket编程、客户/服务端编程、多线程开发、CGI编程、X Windows下的Motif编程等。读者直接或只需稍作修改就可以将它们应用到自己的应用程序开发中。这些范例的源代码可以从配套光盘的...
我们进行多线程编程,可以有多种选择,可以使用WindowsAPI,如果你在使用GTK,也可以使用GTK实现了的线程库,如果你想让你的程序有更多的移植性你好是选择POSIX中的Pthread函数库,我的程序是在Linux下写的,所以我...
Windows(VC6+doc)下C语言多线程聊天室,使用Socket套接字编程,具有多人聊天和私聊的功能,还支持断开重新连接,适合新手学习C语言Socket基础
主要介绍了C语言编程中借助pthreads库进行多线程编程的示例,文中的示例环境为Windows系统,需要的朋友可以参考下
chm格式的核心编程 清晰,初学者必备 请大家放心下载,只看前面几章就会大有收获
主要介绍了Windows系统下C语言编程中Glib库的使用,Glib库在多线程编程中经常可以用到,需要的朋友可以参考下
《Linux多线程服务端编程:使用muduo C++网络库》这本书自今年一月上市...工作中,我没有写过单线程的网络服务程序,没有写过C语言的网络服务程序,也没有写过运行在Windows下的网络服务程序,因此本书不涉及这些内容。
windows编程 VC6.0 网络程序设计 TCP 聊天程序 转发所以发过来的信息 客户端多线程 C语言 客户端与服务器端源代码
开发环境vs2005,开发语言:c语言 基于windows开发的多线程案例,多线程方式实现了TCP协议的滑动窗口协议及选择重传协议 希望对研究多线程编程的童鞋有所帮助
Windows下基于socket的多线程群聊程序,环境是VC6.0。