API CreateThread用法详解
VC中CWinThread类以及和createthreadAPI的区别分析
VC中CWinThread类以及和createthreadAPI的区别分析本⽂实例讲述了VC中CWinThread类以及和createthread API的区别分析,分享给⼤家供⼤家参考。
具体分析如下:CWinThreadCObject└CCmdTarget└CWinThreadCWinThread对象代表在⼀个应⽤程序内运⾏的线程。
运⾏的主线程通常由CWinApp的派⽣类提供;CWinApp由CWinThread 派⽣。
另外,CWinThread对象允许⼀给定的应⽤程序拥有多个线程。
CWinThread⽀持两种线程类型:⼯作者线程(Worker Thread)和⽤户界⾯线程(UI thread)。
⼯作者线程没有收发消息的功能(没有消息队列):例如,在电⼦表格应⽤程序中进⾏后台计算的线程。
⽤户界⾯线程具有收发消息的功能,并处理从系统收到的消息。
CWinApp及其派⽣类是⽤户界⾯线程的例⼦。
其它⽤户界⾯线程也可由CWinThread直接派⽣。
CWinThread类的对象存在于线程的⽣存期。
如果你希望改变这个特性,将m_bAutoDelete设为FALSE。
要使你的代码和MFC是完全线程安全的,CWinThread类是完全必要的。
框架使⽤的⽤来维护与线程相关的信息的线程局部数据由CWinThread对象管理。
由于依赖CWinThread来处理线程局部数据(Thread Local Storage),任何使⽤MFC的线程必须由MFC创建。
例如,由运⾏时函数_beginthreadex创建的线程不能使⽤任何MFC API。
为了创建⼀个线程,调⽤AfxBeginThread函数。
根据你需要⼯作者线程还是⽤户界⾯线程,有两种调⽤AfxBeginThread的格式。
如果你需要⽤户界⾯线程,则将指向你的CWinThread派⽣类的CRuntimeClass的指针传递给AfxBeginThread。
如果你需要创建⼯作者线程,则将指向控制函数的指针和控制函数的参数传递给AfxBeginThread。
c语言创建线程例子
c语言创建线程例子一、什么是线程在计算机科学中,线程是程序执行流的最小单元。
一个线程包含有程序计数器、寄存器集合和栈。
在多线程环境下,多个线程共享同一个进程的资源,但拥有各自的程序计数器、寄存器集合和栈。
线程可以并发执行,可以提高程序的性能和效率。
二、为什么使用线程使用线程可以实现多个任务的并发执行,提高程序的执行效率。
而且线程之间可以共享进程的资源,可以更加高效地利用计算机的硬件资源。
线程的使用可以提供更好的用户体验,比如在图形界面中使用线程可以让程序响应更加迅速,避免出现界面卡顿的情况。
三、C语言中创建线程的方法C语言提供了多种创建线程的方法,下面列举了十个常用的例子:1. 使用pthread库创建线程```c#include <pthread.h>#include <stdio.h>void* thread_func(void* arg) {printf("This is a new thread.\n");return NULL;}int main() {pthread_t tid;pthread_create(&tid, NULL, thread_func, NULL);pthread_join(tid, NULL);printf("Back to main thread.\n");return 0;}```上述代码使用pthread库中的pthread_create函数创建了一个新的线程,并在新线程中执行thread_func函数。
主线程使用pthread_join函数等待新线程执行完毕后再继续执行。
2. 使用Windows API创建线程```c#include <windows.h>#include <stdio.h>DWORD WINAPI thread_func(LPVOID lpParam) {printf("This is a new thread.\n");return 0;}int main() {DWORD dwThreadId;HANDLE hThread = CreateThread(NULL, 0, thread_func, NULL, 0, &dwThreadId);WaitForSingleObject(hThread, INFINITE);printf("Back to main thread.\n");return 0;}```上述代码使用Windows API中的CreateThread函数创建了一个新的线程,并在新线程中执行thread_func函数。
createthread函数使用
createthread函数使用线程是操作系统中一个重要的概念,它支持在同一个程序中多个任务的同时执行,提高了程序的执行效率。
线程的创建是在编程中比较常见的操作,在Windows系统中,可以使用CreateThread函数来创建线程。
CreateThread函数是Windows操作系统应用程序编程接口(API)中提供的一个函数,它可以用来创建一个新的线程,并返回一个线程句柄。
它的原型是:HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_TdwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);CreateThread函数接受6个参数作为输入,其中lpThreadAttributes参数指定新线程的安全属性,dwStackSize指定新线程的堆栈大小,lpStartAddress指定新线程开始执行的函数,lpParameter指定给lpStartAddress函数的参数,dwCreationFlags指定新线程的标志,lpThreadId指定新线程的线程标识符。
CreateThread函数返回一个新线程句柄,用来控制新创建的线程,使用这个句柄可以控制新创建的线程的执行过程,比如暂停、恢复等等。
CreateThread函数提供了一种灵活的机制来创建线程,可以让程序的执行更加高效,如果一个程序需要执行多个任务,使用CreateThread函数可以把这些任务分别分配到不同的线程中,这样可以有效的提高程序的执行效率。
CreateThread函数是一个非常重要的函数,它可以让我们更加方便的创建新的线程,而不是使用原始的操作系统API来创建线程,它可以提供更多的控制,可以更加有效的分配任务,从而提高程序的执行效率。
_beginthreadex和CreateThread
CreateThread()、_beginthreadex()及、AfxBeginThread()函数的讨论2009-05-30 00:27 1157人阅读评论(2) 收藏举报操作系统中线程是非常重要的概念,所以关于线程的创建常常有些困扰人的内容。
好像创建线程的函数很多,那么他们之间的有什么联系与区别呢?正如题目给出的三个函数。
今天看了看Windows核心编程,再找了一些网上的资料,在此想说说这些函数之间的关系和区别。
如有不正确的地方,请各位不吝赐教。
首先,需要说明的是这三个函数都与CreateThread。
CreateThread函数是Windows的一个API函数,其具体的使用方法在MSDN和《Windows核心编程》上都有详细介绍。
主要的作用是创建一个线程。
_beginthreadex函数是C/C++运行库提供的函数,从_beginthreadex函数的源代码,可以看出它的主要动作是:增加了一个名为ptd的_ptiddata的结构的处理,然后在调用CreateThread函数。
_ptiddata是每个线程都拥有自己的专用的数据结构。
关于使用CreateThread代替_beginthreadex的结果以及可能出现的问题在《Windows核心编程》上讲的很清楚:“也许你想知道,如果调用CreateThread,而不是调用C/C++运行期库的_beginthreadex来创建新线程,将会发生什么情况。
当一个线程调用要求_ptiddata结构的C / C + +运行期库函数时,将会发生下面的一些情况(大多数C / C + +运行期库函数都是线程安全函数,不需要该结构)。
首先,C / C + +运行期库函数试图(通过调用T l s G e t Va l u e )获取线程的数据块的地址。
如果返回N U L L作为t i d d a t a块的地址,调用线程就不拥有与该地址相关的_t i d d a t a块。
napi_create_array_with_length用法
napi_create_array_with_length用法Napi是一种用于Node.js的高性能JavaScript API,它提供了许多用于创建、操作和访问数组的方法。
其中,`napi_create_array_with_length`是Napi中的一个函数,用于创建一个具有指定长度的数组。
用法概述:`napi_create_array_with_length`函数接受两个参数:一个表示数组长度,另一个是可选的数组内容。
这个函数会创建一个新的JavaScript数组,并返回一个指向该数组的指针。
函数原型:```scssnapi* napi_create_array_with_length(napi_env env, size_t length);```参数说明:* `env`:Napi环境的指针,用于执行各种Napi操作。
* `length`:要创建的数组的长度。
返回值:* 返回一个指向新创建的数组的指针。
示例用法:下面是一个简单的示例,展示了如何使用`napi_create_array_with_length`函数创建一个具有指定长度的数组:```cppnapi_value CreateArrayWithLength(napi_env env,napi_callback_info info) {size_t length = 5; // 创建一个长度为5的数组napi_value array; // 声明一个空数组变量napi_create_array_with_length(env, length, &array); // 使用函数创建数组return array; // 返回新创建的数组}```注意事项:* `napi_create_array_with_length`函数仅用于创建新的JavaScript数组,不会修改现有的数组。
* 创建的数组的长度可以是任意正整数,但不能超过JavaScript 的数组上限。
vb6.0 createthread创建线程实例
【vb6.0 createthread创建线程实例】在VB6.0中,通过使用CreateThread函数可以创建一个新的线程实例,这为程序员提供了更大的灵活性和控制能力。
在本文中,我们将深入探讨如何在VB6.0中使用CreateThread函数来创建线程实例,并结合实际案例进行详细讲解,以帮助您更好地理解和掌握这一技术。
1. CreateThread函数的基本概念在VB6.0中,CreateThread函数属于Windows API函数,它允许程序员创建一个新的线程实例,并指定线程的起始位置区域和参数。
通过CreateThread函数,我们可以在程序中实现多线程的并发执行,提高程序的效率和响应性。
不过需要注意的是,使用CreateThread函数需要程序员自行管理线程的生命周期和资源,因此需要谨慎使用。
2. CreateThread函数的调用方法在VB6.0中,要使用CreateThread函数,首先需要声明该函数的原型,并定义一个适当的委托来作为线程的起始位置区域。
接下来,我们可以在需要创建线程的地方调用CreateThread函数,并传入相应的参数,以创建线程实例。
在实际调用CreateThread函数时,还需要考虑线程的安全性和同步性,以避免出现竞态条件和资源争夺。
3. 实际案例分析为了更好地理解CreateThread函数的使用方法,下面我们以一个简单的实际案例来说明。
假设我们需要在VB6.0中实现一个多线程的文件下载器,可以同时下载多个文件,并在下载完成后进行相应的处理。
我们可以使用CreateThread函数来创建多个下载线程,每个线程负责下载一个文件;我们可以使用WaitForSingleObject函数来等待所有线程完成下载,并在下载完成后进行相应的处理。
通过这个实际案例,我们可以深入理解和掌握CreateThread函数的使用方法,以及多线程编程的技巧和注意事项。
4. 总结与展望通过本文的介绍和案例分析,我们对VB6.0中CreateThread函数的使用方法有了更深入的了解。
CreateThread()、_beginthreadex()及、AfxBeginThread()函数的讨论
第二,如果不是调用_ e n d t h r e a d e x来终止线程的运行,那么数据块就不会被撤消,内存泄漏就会出现(那么谁还为使用C r e a t e T h r e a d函数创建的线程来调用_ e n d t h r e a d e x呢?)。”对于上面所说的两个问题:我也是有疑问的:使用CreateThread创建线程后,用CloseHandle函数关闭相应的线程句柄,不会对_ptiddata结构进行释放吗? 另外在网上看到一些关于这三个函数的讨论如下: 一直对这三个创建线程的方法都搞不清楚,不知道在什么情况下该用那种方法,下面是从网上摘录的一些帖子:
首先,需要说明的是这三个函数都与CreateThread。CreateThread函数是Windows的一个API函数,其具体的使用方法在 MSDN和《Windows核心编程》上都有详细介绍。主要的作用是创建一个线程。_beginthreadex函数是C/C++运行库提供的函数,从 _beginthreadex函数的源代码,可以看出它的主要动作是:增加了一个名为ptd的_ptiddata的结构的处理,然后在调用CreateThread函数。_ptiddata是每个线程都拥有自己的专用的数据结构。关于使用CreateThread代替_beginthreadex的结果以及可能出现的问题在《Windows核心编程》上讲的很清楚: “也许你想知道,如果调用CreateThread,而不是调用C/C++运行期库的_beginthreadex来创建新线程,将会发生什么情况。当一个线程调用要求_ptiddata结构的C / C + +运行期库函数时,将会发生下面的一些情况(大多数C / C + +运行期库函数都是线程安全函数,不需要该结构)。
异步方式winAPI串口通信
使用winAPI串口通信(二)分类:Windows转载2009-09-23 16:51 263人阅读评论(0) 收藏举报采用同步方式的查询方式读取串口数据时,若由于串口操作耗费较长的时间,则程序会被挂起.为解决这种问题,可以在读取数据时采用重叠I/O操作.此时,读写数据的操作在单独的线程中进行,发出读写要求的主线程可以继续运行.当读写数据成功后,读写数据线程可以通过某种方式通知主线程.两个线程协调工作 ,可以明显提高程序的效率.为了实现重叠I/O操作,主要有如下几个编程步骤: 定义全局变量、创建串口、发出读写操作、读写线程函数的建立、关闭串口等.1. 定义全局变量HANDLE hCom; //串口句柄DWORD ThreadProcWrite(LPVOID pParam); //写线程函数DWORD ThreadProcRead(LPVOID pParam); //读线程函数OVERLAPPED Wol = { 0 }; //写操作OVERLAPPED结构变量OVERLAPPED Rol = { 0 }; //读操作OVERLAPPED结构变量HANDLE hThreadWrite; //写线程句柄HANDLE hThreadRead; //读线程句柄HWND hWnd; //窗口句柄2. 创建串口hCom = CreateFile ( "COM2",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,//使用重叠方式NULL );if( hCom != INVALID_HANDLE_VALUE){SetupComm(hCom,1024,512);DCB myDCB;GetCommState( hCom,&myDCB);myDCB.BaudRate=CBR_19200;myDCB.fBinary=TRUE;myDCB.fParity=TRUE;myDCB.ByteSize=8;myDCB.Parity=ODDPARITY;myDCB.StopBits=ONESTOPBIT;SetCommState(hCom,&myDCB);}else{AfxMessageBox("创建串口失败!");}hWnd = GetSafeHwnd(); //获取当前窗口的句柄3. 发出读写操作(1) 读操作在读操作中,只是启动读线程.实际的读操作在读线程函数中完成.DWORD dwThreadID;DWORD dwParam;hThreadRead = CreateThread ( NULL,0,(LPTHREAD_START_ROUTINE)ThreadProcRead,&dwParam,0, //创建线程后,立即执行该线程&dwThreadID);if(hThreadRead==NULL){AfxMessageBox("读线程创建失败!");}CreateThread()函数用于创建一个线程.HANDLE CreateThread (//线程安全属性,NULL表示该线程不能被继承LPSECURITY_ATTRIBUTES lpThreadAttributes,//初始化栈大小.0表示默认值或按调用栈线程配置DWORD dwStackSize,//执行函数名称LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter, //向新线程传递的参数DWORD dwCreationFlags, //创建标志.0表示创建后立即执行LPDWORD lpThreadId);(2) 写操作在写操作中,同样只是启动写线程.实际的写操作在写线程函数中完成.DWORD dwThreadID;DWORD dwParam;hThreadWrite = CreateThread( NULL,0,(LPTHREAD_START_ROUTINE)ThreadProcWrite,&dwParam,0,&dwThreadID);if(hThreadWrite==NULL){AfxMessageBox("写线程创建失败!");}4.读写线程函数的建立读写的实际操作在读写线程函数中执行. 这两个函数都是全局函数.(1) 读线程函数在读线程函数中,首先应初始化重叠结构Rol的成员hEvent,将其设置为无信号状态.当读操作完成或出现通信错误时,该变量会被自动设置为有信号状态.接下来就可以使用ReadFile()函数发出读命令.若该读函数返回TRUE,说明读操作已经完成,可以处理读取的数据.若该读函数返回FALSE,说明读操作未完成.此时使用WaitForSingleObject()函数等待读操作的结构。
delphi中的线程类详解
delphi中的线程类Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchronize 的用法就完了。
然而这并不是多线程编程的全部,我写此文的目的在于对此作一个补充。
线程本质上是进程中一段并发运行的代码。
一个进程至少有一个线程,即所谓的主线程。
同时还可以有多个子线程。
当一个进程中用到超过一个线程时,就是所谓的“多线程”。
那么这个所谓的“一段代码”是如何定义的呢?其实就是一个函数或过程(对Delphi而言)。
如果用Windows API来创建线程的话,是通过一个叫做CreateThread的API函数来实现的,它的定义为:HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);其各参数如它们的名称所说,分别是:线程属性(用于在NT下进行线程的安全属性设置,在9X下无效),堆栈大小,起始地址,参数,创建标志(用于设置线程创建时的状态),线程ID,最后返回线程Handle。
其中的起始地址就是线程函数的入口,直至线程函数结束,线程也就结束了。
整个线程的执行过程如下图所示:因为CreateThread参数很多,而且是Windows的API,所以在C Runtime Library里提供了一个通用的线程函数(理论上可以在任何支持线程的OS中使用):unsigned long _beginthread(void (_USERENTRY *__start)(void *), unsigned __stksize, void *__arg);Delphi也提供了一个相同功能的类似函数:function BeginThread(SecurityAttributes: Pointer; StackSize: LongWord; ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord; var ThreadId: LongWord): Integer;这三个函数的功能是基本相同的,它们都是将线程函数中的代码放到一个独立的线程中执行。
createthread用法
createthread用法CreateThread 是windows API函数中的一员之一,它被用于创建一个子线程。
CreateThread主要追求的是更细致地掌控线程的实现,弥补了windows系统CreateProcess函数对进程实现的不足,若要了解CreateProcess用法,可参考Windows API-CreateProcess用法。
一、CreateThread概述CreateThread作为一个windows API函数,其语法如下:HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,__drv_aliasesMem __drv_eval(==0)__drv_aliasesMem LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);各参数解释如下:1. lpThreadAttributes: 决定新线程是否可以被继承。
若为NULL,新线程就可以被创建进程中的任何线程继承。
若有其他值,则新线程只能被能登录进程对象的线程访问。
2. dwStackSize: 线程栈的大小。
通常该参数保持为0即可,以使用默认的线程栈大小。
3. lpStartAddress: 线程函数的执行地址,其格式必须为DWORD CALLBACK函数的地址。
该线程函数无论返回什么结果,都会被传回给CreateThread的调用者。
回调函数一般不会传入参数,或者直接通过传入指针来获得访问上下文中的一些数据。
4. lpParameter: 指向一个可选的指针,该指针会传递给线程函数(即回调函数)。
5. dwCreationFlags: 线程的创建标志。
可选择的标志如下:· CREATE_SUSPENDED:新线程被调用后暂停执行· STACK_SIZE_PARAM_IS_A_RESERVATION:忽略dwStackSize,取默认值· CREATE_DETACHED:新线程不可被其他线程访问除此之外,还有CREATE_NO_WINDOW等标志,可供根据具体需求选择。
CreateThread用法详解
CreateThread用法详解今天我给大家讲一讲C++中的多线程编程技术,C++本身并没有提供任何多线程机制,但是在windows下,我们可以调用SDK win32 api来编写多线程的程序,下面我就此简单的讲一下:创建线程的函数HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, // SDSIZE_T dwStackSize, // initial stack sizeLPTHREAD_START_ROUTINE lpStartAddress, // thread functionLPVOID lpParameter, // thread argumentDWORD dwCreationFlags, // creation optionLPDWORD lpThreadId // thread identifier);在这里我们只用到了第三个和第四个参数,第三个参数传递了一个函数的地址,也是我们要指定的新的线程。
第四个参数是传给新线程的参数指针eg1:#include <iostream>#include <windows.h>using namespace std;DWORD WINAPI Fun(LPVOID lpParamter){while(1) { cout<<"Fun display!"<<endl; }}int main(){HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);CloseHandle(hThread);while(1) { cout<<"main display!"<<endl; }return 0;}我们可以看到主线程(main函数)和我们自己的线程(Fun函数)是随机地交替执行的,但是两个线程输出太快,使我们很难看清楚,我们可以使用函数VOID Sleep(DWORD dwMilliseconds // sleep time);来暂停线程的执行,dwMilliseconds表示千分之一秒,所以Sleep(1000);表示暂停1秒eg2:#include <iostream>#include <windows.h>using namespace std;DWORD WINAPI Fun(LPVOID lpParamter){while(1) { cout<<"Fun display!"<<endl; Sleep(1000);}}int main(){HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);CloseHandle(hThread);while(1) { cout<<"main display!"<<endl; Sleep(2000);}return 0;}执行上述代码,这次我们可以清楚地看到在屏幕上交错地输出Fun display!和main display!,我们发现这两个函数确实是并发运行的,细心的读者可能会发现我们的程序是每当Fun函数和main函数输出内容后就会输出换行,但是我们看到的确是有的时候程序输出换行了,有的时候确没有输出换行,甚至有的时候是输出两个换行。
多线程CreateThread函数的用法
多线程CreateThread函数的⽤法CreateThread当使⽤CreateProcess调⽤时,系统将创建⼀个进程和⼀个主线程。
CreateThread将在主线程的基础上创建⼀个新线程,⼤致做如下步骤: 1在内核对象中分配⼀个线程标识/句柄,可供管理,由CreateThread返回 2把线程退出码置为STILL_ACTIVE,把线程挂起计数置1 3分配context结构 4分配两页的物理存储以准备栈,保护页设置为PAGE_READWRITE,第2页设为PAGE_GUARD 5lpStartAddr和lpvThread值被放在栈顶,使它们成为传送给StartOfThread的参数 6把context结构的栈指针指向栈顶(第5步)指令指针指向startOfThread函数HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, //线程安全相关的属性,常置为NULLSIZE_T dwStackSize, //新线程的初始化栈在⼤⼩,可设置为0LPTHREAD_START_ROUTINE lpStartAddress, //被线程执⾏的回调函数,也称为线程函数LPVOID lpParameter, //传⼊线程函数的参数,不需传递参数时为NULLDWORD dwCreationFlags, //控制线程创建的标志LPDWORD lpThreadId //传出参数,⽤于获得线程ID,如果为NULL则不返回线程ID);第⼀个参数是指向SECURITY_ATTRIBUTES型态的结构的指针。
在Windows 98中忽略该参数。
在Windows NT中,它被设为NULL。
第⼆个参数是⽤于新线程的初始堆栈⼤⼩,默认值为0。
在任何情况下,Windows根据需要动态延长堆栈的⼤⼩。
第三个参数是指向线程函数的指标。
函数名称没有限制,但是必须以下列形式声明:DWORD WINAPI ThreadProc (PVOID pParam) ;第四个参数为传递给ThreadProc的参数。
操作系统API使用方法
系统API使用方法一、OpenProcess函数用来打开一个已存在的进程对象,并返回进程的句柄。
HANDLE OpenProcess(DWORD dwDesiredAccess, //渴望得到的访问权限(标志)BOOL bInheritHandle, // 是否继承句柄DWORD dwProcessId// 进程标示符); 用来打开一个已存在的进程对象,并返回进程的句柄。
返回值:如成功,返回值为指定进程的句柄。
如失败,返回值为空,可调用GetLastError获得错误代码。
举例HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pID );附: BOOL ReadProcessMemory( HANDLE hProcess, PVOID pvAddressRemote, PVOID pvBufferLocal, DWORD dwSize, PDWORD pdwNumBytesRead);参数hProcess //为远程进程的句柄pvAddressRemote //用于指明远程进程中的地址pvBufferLocal //是本地进程中的内存地址dwSize //是需要传送的字节数pdwNumBytesRead和pdwNumBytesWritten //用于指明实际传送的字节数.当函数返回时,可以查看这两个参数的值.二、GetCurrentProcessHANDLE WINAPI GetCurrentProcess( VOID );说明:获取当前进程的一个句柄返回值:为当前进程的句柄注解:只要当前进程需要一个进程句柄,就可以使用这个伪句柄。
该句柄可以复制,但不可继承。
不必调用CloseHandle函数来关闭这个句柄三、GetPriorityClass、DWORD WINAPI GetPriorityClass(__in HANDLE hProcess );说明:获取特定进程的优先级别返回值:Long,进程的优先级,零表示失败。
zwcreatethreadex参数
评估和撰写文章内容中……完成中……完成中……标题:深度解读zwcreatethreadex参数:深入理解Windows多线程编程在Windows多线程编程中,zwcreatethreadex参数扮演着重要的角色。
本文将全面评估zwcreatethreadex参数的概念、用法和深度,并据此撰写一篇有价值的文章,帮助读者更全面、深刻地理解Windows多线程编程。
1. 概念和基本用法:在Windows API中,CreateThread是创建一个线程的基本函数。
而zwcreatethreadex参数则是在CreateThread基础上的一个扩展参数,其作用是……在使用zwcreatethreadex参数创建线程时,需要注意的是……通过zwcreatethreadex参数,我们可以实现……2. 深入理解zwcreatethreadex参数:2.1 zwcreatethreadex参数的内部实现原理2.2 zwcreatethreadex参数与其他Windows多线程函数的关系2.3 zwcreatethreadex参数的使用场景和注意事项2.4 zwcreatethreadex参数的高级用法和扩展性3. 总结和回顾:通过对zwcreatethreadex参数的深入讨论,我们不仅学习了其基本概念和用法,还深入理解了其内部实现原理和高级用法。
整体而言,zwcreatethreadex参数在Windows多线程编程中扮演着重要的角色,对于提升程序的性能和响应速度有着重要的意义。
个人观点和理解:作为一名Windows多线程编程的爱好者,我深深体会到zwcreatethreadex参数对于程序性能的提升和多线程并发操作的重要性。
在实际项目中,合理使用zwcreatethreadex参数可以极大地提高程序的并发能力和响应速度,对于提升用户体验有着重要的意义。
我认为深入理解和熟练掌握zwcreatethreadex参数是每个Windows 多线程开发者都应该具备的技能。
利用Windows线程控制API函数完成同步控制实验
利用Windows线程控制API函数完成同步控制实验1.实验目的:解决生产者与消费者的同步控制问题,编程实现。
2.实验要求:根据输入的M、N和K的值,并假定M个生产者和N个消费者同时存在,每个生产者和消费者设置一个延迟时间属性,生产者线程和消费者线程的调度顺序根据延迟后时间按照先来先服务算法调度执行,要求设计并展示M个生产者和N个消费者异步执行情况(通过输出显示当前哪个线程在执行,哪个线程阻塞)。
3.实现原理:创建一组“生产者”线程和一组“消费者”线程,并建立一个长度为K的缓冲区。
“生产者”向缓冲区输入数据,“消费者”从缓冲区读出数据。
当缓冲区满时,“生产者”必须阻塞,等待“消费者”取走缓冲区数据后将其唤醒。
当缓冲区空时,“消费者”阻塞,等待“生产者”生产了产品后将其唤醒。
用信号量实现“生产者”与“消费者”线程之间的同步。
4.函数:1)CreateMutex:创建互斥对象HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName);参数及说明:lpMutexAttributes参数是安全属性,一般设置为NULL;bInitia10wner 表明创建后是否被创建线程所“拥有”;lpName 是互斥对象名。
2)ReleaseMutex:释放互斥对象BOOL WINAPI ReleaseMutex( HANDLE hMutex;)3)CreateSemaphore:创建信号量HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCTSTR lpName);参数及说明:lpSemaphoreAttributes 参数是安全属性,指向LPSECURITY_ATTRIBUTES 结构,若为NULL则表示使用默认属性lInitialCount 参数是初始的计数值,lMaximumCount 参数是最大的计数值lpName 参数来给信号量对象命名。
CreateThread使用(六个参数介绍)
CreateThread使用(六个参数介绍)CreateThread使用(六个参数介绍)function CreateThread(lpThreadAttributes: Pointer; {安全设置}dwStackSize: DWORD; {堆栈大小} lpStartAddress: TFNThreadStartRoutine; {入口函数}lpParameter: Pointer; {函数参数} dwCreationFlags: DWORD; {启动选项}var lpThreadId: DWORD {输出线程ID }): THandle; stdcall; {返回线程句柄}1、返回值:返回线程句柄"句柄" 类似指针, 但通过指针可读写对象, 通过句柄只是使用对象;有句柄的对象一般都是系统级别的对象(或叫内核对象); 之所以给我们的是句柄而不是指针, 目的只有一个: "安全";貌似通过句柄能做很多事情, 但一般把句柄提交到某个函数(一般是系统函数)后, 我们也就到此为止很难了解更多了; 事实上是系统并不相信我们.不管是指针还是句柄, 都不过是内存中的一小块数据(一般用结构描述), 微软并没有公开句柄的结构细节, 猜一下它应该包括: 真实的指针地址、访问权限设置、引用计数等等.既然CreateThread 可以返回一个句柄, 说明线程属于"内核对象".实际上不管线程属于哪个进程, 它们在系统的怀抱中是平等的; 在优先级(后面详谈)相同的情况下, 系统会在相同的时间间隔内来运行一下每个线程, 不过这个间隔很小很小, 以至于让我们误以为程序是在不间断地运行.这时你应该有一个疑问: 系统在去执行其他线程的时候, 是怎么记住前一个线程的数据状态的?有这样一个结构TContext, 它基本上是一个CPU 寄存器的集合, 线程是数据就是通过这个结构切换的, 我们也可以通过GetThreadContext 函数读取寄存器看看.附上这个结构TContext(或叫: CONTEXT、_CONTEXT) 的定义: PContext = ^TContext;_CONTEXT = recordContextFlags: DWORD;Dr0: DWORD;Dr1: DWORD;Dr2: DWORD;Dr3: DWORD;Dr6: DWORD;Dr7: DWORD;FloatSave: TFloatingSaveArea;SegGs: DWORD;SegFs: DWORD;SegEs: DWORD;SegDs: DWORD;Edi: DWORD;Esi: DWORD;Ebx: DWORD;Edx: DWORD;Ecx: DWORD;Eax: DWORD;Ebp: DWORD;Eip: DWORD;SegCs: DWORD;EFlags: DWORD;Esp: DWORD;SegSs: DWORD;end;2、参数6:输出线程IDCreateThread 的最后一个参数是"线程的ID";既然可以返回句柄, 为什么还要输出这个ID? 现在我知道的是:1、线程的ID 是唯一的; 而句柄可能不只一个, 譬如可以用GetCurrentThread 获取一个伪句柄、可以用DuplicateHandle 复制一个句柄等等.2、ID 比句柄更轻便.在主线程中GetCurrentThreadId、MainThreadID获取的都是主线程的ID. MainInstance: Indicates the instance handle for the main executable.Use MainInstance to obtain the instance handle for the main executable of an application. This is useful in applications that use runtime libraries or packages, when you need the handle for the executable rather than for the library.3、参数5:启动选项CreateThread 的倒数第二个参数dwCreationFlags(启动选项) 有两个可选值: 0: 线程建立后立即执行入口函数;CREATE_SUSPENDED: 线程建立后会挂起等待.ResumeThread 恢复线程的运行; SuspendThread 挂起线程.这两个函数的参数都是线程句柄, 返回值是执行前的挂起计数.什么是挂起计数?SuspendThread 会给这个数+1; ResumeThread 会给这个数-1; 但这个数最小是0.当这个数= 0 时, 线程会运行; > 0 时会挂起.如果被SuspendThread 多次, 同样需要ResumeThread 多次才能恢复线程的运行.ResumeThread 和SuspendThread 分别对应TThread 的Resume 和Suspend 方法, 很好理解.4、参数4:函数参数线程入口函数的参数是个无类型指针(Pointer), 用它可以指定任何数据; 本例是把鼠标点击窗体的坐标传递给线程的入口函数, 每次点击窗体都会创建一个线程.5、参数3:入口函数指针到了入口函数了, 学到这个地方, 我查了一个入口函数的标准定义, 这个函数的标准返回值应该是DWORD, 不过这函数在Delphi 的System 单元定义的是: TThreadFunc = function(Parameter: Pointer): Integer; 我以后会尽量使用DWORD 做入口函数的返回值.这个返回值有什么用呢?等线程退出后, 我们用GetExitCodeThread 函数获取的退出码就是这个返回值!如果线程没有退出, GetExitCodeThread 获取的退出码将是一个常量STILL_ACTIVE (259); 这样我们就可以通过退出码来判断线程是否已退出.还有一个问题: 前面也提到过, 线程函数不能是某个类的方法! 假如我们非要线程去执行类中的一个方法能否实现呢?尽管可以用Addr(类名.方法名) 或MethodAddress('published 区的方法名') 获取类中方法的地址, 但都不能当做线程的入口函数, 原因可能是因为类中的方法的地址是在实例化为对象时动态分配的.后来换了个思路, 其实很简单: 在线程函数中再调用方法不就得了, 估计TThread 也应该是这样.CreateThread 第三个参数是函数指针, 新线程建立后将立即执行该函数, 函数执行完毕, 系统将销毁此线程从而结束多线程的故事.6、参数2:堆栈大小栈是私有的但堆是公用的CreateThread 的第二个参数是分配给线程的堆栈大小.这首先这可以让我们知道: 每个线程都有自己独立的堆栈(也拥有自己的消息队列).什么是堆栈? 其实堆是堆、栈是栈, 有时"栈" 也被叫做"堆栈".它们都是进程中的内存区域, 主要是存取方式不同(栈:先进后出; 堆:先进先出);"栈"(或叫堆栈)适合存取临时而轻便的变量, 主要用来储存局部变量; 譬如for i := 0 to 99 do 中的i 就只能存于栈中, 你把一个全局的变量用于for 循环计数是不可以的.现在我们知道了线程有自己的"栈", 并且在建立线程时可以分配栈的大小. 前面所有的例子中, 这个值都是0, 这表示使用系统默认的大小, 默认和主线程栈的大小一样, 如果不够用会自动增长;那主线程的栈有多大? 这个值是可以设定的: Project -> Options -> Delphi Compiler -> Linking(如图)栈是私有的但堆是公用的, 如果不同的线程都来使用一个全局变量有点乱套; 为解决这个问题Delphi 为我们提供了一个类似var 的ThreadVar 关键字, 线程在使用ThreadVar 声明的全局变量时会在各自的栈中留一个副本, 这样就解决了冲突. 不过还是尽量使用局部变量, 或者在继承TThread 时使用类的成员变量, 因为ThreadVar 的效率不好, 据说比局部变量能慢10 倍.7、参数1:安全设置CreateThread 的第一个参数lpThreadAttributes 是指向TSecurityAttributes 结构的指针, 一般都是置为nil, 这表示没有访问限制; 该结构的定义是://TSecurityAttributes(又名: SECURITY_ATTRIBUTES、_SECURITY_ATTRIBUTES)_SECURITY_ATTRIBUTES = recordnLength: DWORD; {结构大小}lpSecurityDescriptor: Pointer; {默认nil; 这是另一个结构TSecurityDescriptor 的指针}bInheritHandle: BOOL; {默认False, 表示不可继承}end;//TSecurityDescriptor(又名: SECURITY_DESCRIPTOR、_SECURITY_DESCRIPTOR) _SECURITY_DESCRIPTOR = record Revision: Byte;Sbz1: Byte;Control: SECURITY_DESCRIPTOR_CONTROL;Owner: PSID;Group: PSID;Sacl: PACL;Dacl: PACL;end;够复杂的, 但我们在多线程编程时不需要去设置它们, 大都是使用默认设置(也就是赋值为nil).我觉得有必要在此刻了解的是: 建立系统内核对象时一般都有这个属性(TSecurityAttributes);在接下来多线程的课题中要使用一些内核对象, 不如先盘点一下, 到时碰到这个属性时给个nil 即可, 不必再费神.{建立事件}function CreateEvent(lpEventAttributes: PSecurityAttributes; {!}bManualReset: BOOL;bInitialState: BOOL;lpName: PWideChar): THandle; stdcall;{建立互斥}function CreateMutex(lpMutexAttributes: PSecurityAttributes; {!}bInitialOwner: BOOL;lpName: PWideChar): THandle; stdcall;{建立信号}function CreateSemaphore(lpSemaphoreAttributes: PSecurityAttributes; {!}lInitialCount: Longint;lMaximumCount: Longint;lpName: PWideChar): THandle; stdcall;{建立等待计时器}function CreateWaitableTimer(lpTimerAttributes: PSecurityAttributes; {!}bManualReset: BOOL;lpTimerName: PWideChar): THandle; stdcall;上面的四个系统内核对象(事件、互斥、信号、计时器)都是线程同步的手段, 从这也能看出处理线程同步的复杂性; 不过这还不是全部, Windows Vista 开始又增加了Condition variables(条件变量)、Slim Reader-Writer Locks(读写锁)等同步手段.不过最简单、最轻便(速度最快)的同步手段还是CriticalSection(临界区), 但它不属于系统内核对象, 当然也就没有句柄、没有TSecurityAttributes 这个安全属性, 这也导致它不能跨进程使用; 不过写多线程时一般不用跨进程啊, 所以CriticalSection 应该是最常用的同步手段.。
createprocess异步读取管道数据的代码实现-概述说明以及解释
createprocess异步读取管道数据的代码实现-概述说明以及解释1.引言1.1 概述在现代软件开发中,经常会遇到需要创建子进程并与之交互的场景。
而在子进程的执行过程中,我们往往需要从子进程的输出中获取数据,以便进行后续的处理和分析。
而CreateProcess函数是Windows系统中用于创建新进程的API函数,它可以实现创建子进程并与之进行通信的功能。
然而,在使用CreateProcess函数创建子进程时,我们常常需要读取子进程的输出信息,以便及时处理。
但是由于子进程的输出是通过管道进行传输的,而管道的读取操作是阻塞式的,即当没有数据可读时,读取操作会一直阻塞,直到有数据可读为止。
这就给我们的程序带来了一定的困扰,因为当程序阻塞在读取管道的地方时,无法进行其他重要的操作。
为了解决这个问题,我们可以利用异步读取管道数据的方法。
异步读取管道数据的主要思想是通过创建一个子线程,在该线程中进行管道的读取操作,并将读取到的数据暂存起来,供主线程使用。
这样,主线程可以继续进行其他操作,而不会因为阻塞在读取管道的地方而无法前进。
本文将主要介绍如何利用CreateProcess函数创建子进程,并通过异步读取管道数据的方式,实现与子进程的交互。
首先,我们将介绍如何创建进程并建立管道;接着,我们将详细讲解如何实现异步读取管道数据的方法。
最后,我们将进行本文的总结和结论。
接下来,让我们开始了解如何创建进程并建立管道的具体步骤。
1.2文章结构文章结构:本文共分为以下几个部分:1. 引言:在这一部分,将对文章的主题进行概述,介绍本文的结构和目的。
2. 正文:本文正文分为两个主要部分:2.1 创建进程并建立管道:在这一部分,将详细介绍如何使用CreateProcess函数创建进程,并建立起进程间通信的管道。
2.2 实现异步读取管道数据:这是本文的重点部分,将介绍如何通过异步方式读取管道中的数据,以提高程序的效率和性能。
CreateThread()与beginthread()的区别详细解析
CreateThread()与beginthread()的区别详细解析我们知道在Windows下创建⼀个线程的⽅法有两种,⼀种就是调⽤Windows API CreateThread()来创建线程;另外⼀种就是调⽤MSVC CRT的函数_beginthread()或_beginthreadex()来创建线程。
相应的退出线程也有两个函数Windows API的ExitThread()和CRT的_endthread()。
这两套函数都是⽤来创建和退出线程的,它们有什么区别呢?很多开发者不清楚这两者之间的关系,他们随意选⼀个函数来⽤,发现也没有什么⼤问题,于是就忙于解决更为紧迫的任务去了,⽽没有对它们进⾏深究。
等到有⼀天忽然发现⼀个程序运⾏时间很长的时候会有细微的内存泄露,开发者绝对不会想到是因为这两套函数⽤混的结果。
根据Windows API和MSVC CRT的关系,可以看出来_beginthread()是对CreateThread()的包装,它最终还是调⽤CreateThread()来创建线程。
那么在_beginthread()调⽤CreateThread()之前做了什么呢?我们可以看⼀下_beginthread()的源代码,它位于CRT源代码中的thread.c。
我们可以发现它在调⽤CreateThread()之前申请了⼀个叫_tiddata的结构,然后将这个结构⽤_initptd()函数初始化之后传递给_beginthread()⾃⼰的线程⼊⼝函数_threadstart。
_threadstart⾸先把由_beginthread()传过来的_tiddata结构指针保存到线程的显式TLS数组,然后它调⽤⽤户的线程⼊⼝真正开始线程。
在⽤户线程结束之后,_threadstart()函数调⽤_endthread()结束线程。
并且_threadstart还⽤__try/__except将⽤户线程⼊⼝函数包起来,⽤于捕获所有未处理的信号,并且将这些信号交给CRT处理。
mfc中使用createthread
当在MFC(Microsoft Foundation Class)中使用CreateThread时,我们需要深入了解其深度和广度,以便更好地理解这一主题。
CreateThread是一个用于在Windows程序中创建线程的函数,对于多线程编程来说是非常重要的。
下面将对这一主题进行全面评估,并撰写一篇有价值的文章。
在MFC中使用CreateThread可以带来很多好处,但也需要注意一些潜在的问题。
我们需要了解线程的基本概念,包括什么是线程、线程的生命周期、线程的同步与通信等。
这些基础知识能够为我们深入理解CreateThread函数的使用提供重要的基础。
我们需要探讨CreateThread函数的具体用法和参数含义。
通过分析CreateThread的函数原型和参数,我们可以了解到它的调用方式、线程的入口函数、线程的优先级、堆栈大小等信息。
在使用CreateThread时,需要格外注意传递给线程函数的参数,以确保线程能够正确地获取所需的数据。
在文章中,我们将重点强调CreateThread的使用细节,例如如何在MFC应用程序中创建新线程,如何处理线程函数返回值,如何安全地结束线程,以及如何处理线程间的同步与通信。
我们还需要讨论在使用CreateThread时可能遇到的常见问题和注意事项,例如线程安全性、内存管理等方面的考虑。
在全面评估了CreateThread的深度和广度之后,我们将总结文章内容,回顾性地概括使用CreateThread的要点和注意事项。
这样可以使读者全面、深刻地理解与掌握CreateThread的使用方法,并且能够灵活应用于实际的开发工作中。
个人观点上,我认为在MFC中使用CreateThread需要谨慎对待,尤其是在多线程编程中。
虽然CreateThread为我们提供了一个方便的接口来创建线程,但在实际使用中需要注意线程安全性、内存管理等问题,以避免可能出现的潜在风险。
在撰写文章时,有序地进行排版是非常重要的。
vb createthread用法(一)
vb createthread用法(一)VB CreateThread用法详解VB CreateThread是一个用于创建线程的函数,可以在Visual Basic编程环境中使用。
本文将详细介绍它的用法。
1. 简介CreateThread函数是Windows API函数之一,可以用于在VB中创建一个新线程。
线程是程序中独立执行的一段代码,它可以并发执行,提高程序的运行效率。
2. 函数原型CreateThread函数的函数原型如下:Private Declare Function CreateThread Lib "kernel32 " (ByVal lpThreadAttributes As Long, ByVal dwStackSize A s Long, ByVal lpStartAddress As Long, ByVal lpParameter As Long, ByVal dwCreationFlags As Long, ByVal lpThreadId As Long) As Long3. 参数说明CreateThread函数的参数解释如下:•lpThreadAttributes:线程属性,一般使用0或NULL表示默认属性。
•dwStackSize:线程栈大小,可以指定线程栈的大小,一般使用0表示默认大小。
•lpStartAddress:线程起始地址,指向线程的入口函数。
•lpParameter:指向传递给线程的参数,可以是任意类型的数据。
•dwCreationFlags:线程创建标识,可以指定线程的各种属性,如优先级等。
•lpThreadId:线程ID,用于获取新线程的标识符。
4. 使用示例下面列举了几个常见的CreateThread函数的使用示例:•创建一个新线程并执行指定的函数:Private Function MyThreadFunc(ByVal lpParameter As Long) As Long' 线程要执行的代码End FunctionSub Main()Dim hThread As LonghThread = CreateThread(0, 0, AddressOf MyThreadFunc, 0, 0, 0)' 等待线程执行完成WaitForSingleObject hThread, INFINITE' 关闭线程句柄CloseHandle hThreadEnd Sub•传递参数给线程函数:Private Function MyThreadFunc(ByVal lpParameter As Long) As LongDim nCount As LongnCount = lpParameter' 线程要执行的代码End FunctionSub Main()Dim hThread As LongDim nParam As LongnParam = 10hThread = CreateThread(0, 0, AddressOf MyThreadFunc, nParam, 0, 0)' 等待线程执行完成WaitForSingleObject hThread, INFINITE' 关闭线程句柄CloseHandle hThreadEnd Sub•设置线程的优先级:Private Function MyThreadFunc(ByVal lpParameter As Long) As Long' 线程要执行的代码End FunctionSub Main()Dim hThread As LonghThread = CreateThread(0, 0, AddressOf MyThreadFunc, 0, THREAD_PRIORITY_NORMAL, 0)' 等待线程执行完成WaitForSingleObject hThread, INFINITE' 关闭线程句柄CloseHandle hThreadEnd Sub以上示例只是CreateThread函数的一些基本用法,具体的使用方式可以根据实际需求进行扩展和修改。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
); 来暂停线程的执行,dwMilliseconds 表示千分之一秒,所以
Sleep(1000); 表示暂停 1 秒
eg2:
#include <iostream> #include <windows.h> using namespace std;
那么,是不是 eg2 的代码我们就不可以让它正确的运行呢?答案当然是否,下面我就来讲 一下怎样才能让 eg2 的代码可以正确运行。这涉及到多线程的同步问题。对于一个资源被多 个线程共用会导致程序的混乱,我们的解决方法是只允许一个线程拥有对共享资源的独占,
这样就能够解决上面的问题了。
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, // SD
DWORD WINAPI Fun(LPVOID lpParamter) {
while(1) { cout<<"Fun display!"<<endl; Sleep(1000);} }
int main() {
HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL); CloseHandle(hThread); while(1) { cout<<"main display!"<<endl; Sleep(2000);} return 0; } 执行 上述 代码, 这次 我们可 以清 楚地看 到在 屏幕上 交错 地输出 Fun display!和 main dis play!,我们发 现这两个函数确实 是并发运行的, 细心的读者可能会 发现我们的程序 是每 当 Fun 函数和 main 函数输出内容后就会输出换行,但是我们看到的确是有的时候程序输出 换行了,有的时候确没有输出换行,甚至有的时候是输出两个换行。这是怎么回事?下面我 们把程序改一下看看: eg3:
#include <iostream> #include <windows.h> using namespace std;
DWORD WINAPI Fun(LPVOID lpParamter) {
while(1) { cout<<"Fun display!\n"; Sleep(1000);} }
int main() {
HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL); CloseHandle(hThread); while(1) { cout<<"main display!\n"; Sleep(2000);} return 0; } 我们再次运行这个程序,我们发现这时候正如我们预期的,正确地输出了我们想要输出的 内容并且格式也是正确的。下面我就来讲一下此前我们的程序为什么没有正确的运行。多线 程的程序时并发地运行的,多个线程之间如果公用了一些资源的话,我们并不能保证这些资 源都能正确地被利用,因为这个时候资源并不是独占的,举个例子吧: eg4: 加入有一个资源 int a = 3 有一个线程函数 selfAdd() 该函数是使 a = a+a 又有一个线程函数 selfSub() 该函数是使 a = a-a
创建线程的函数
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
SIZE_T dwStackSize,
// initial stack size
LPTHREAD_START_ROUTINE lpStartAddress, // thread function
// handle to object
DWORD dwMilliseconds // time-out interval
); 第一个参数指定所申请的资源的句柄,第二个参数一般指定为 INFINITE,表示如果没有申 请到资源就一直等待该资源,如果指定为 0,表示一旦得不到资源就返回,也可以具体地指 定等待多久才返回,单位是千分之一秒。好了,该到我们来解决 eg2 的问题的时候了,我们 可以把 eg2 做一些修改,如下
WaitForSingleObject(hMutex, INFINITE); cout<<"main display!"<<endl; Sleep(2000); ReleaseMutex(hMutex); } return 0; }
运行代码正如我速成为做挂达人。
} }
int main() {
HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL); hMutex = CreateMutex(NULL, FALSE, "screen"); CloseHandle(hThread); while(1) {
LPVOID lpParameter,
// thread argument
DWORD dwCreationFlags,
// creation option
LPDWORD lpThreadId
// thread identifier
);
在这里我们只用到了第三个和第四个参数,第三个参数传递了一个函数的地址,也是我们要 指定的新的线程。第四个参数是传给新线程的参数指针
BOOL ReleaseMutex( HANDLE hMutex // handle to mutex
); 该函数用于释放一个独占资源,进程一旦释放该资源,该资源就不再属于它了,如果还要用 到,需要重新申请得到该资源。申请资源的函数如下
DWORD WaitForSingleObject(
HANDLE hHandle,
Api CreateThread 用法详解速成为做挂达人。
今天我给大家讲一讲 C++中的多线程编程技术,C++本身并没有提供任何多线程机制,但是 在 windows 下,我们可以调用 SDK win32 api 来编写多线程的程序,下面我就此简单的讲一 下:
HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL); CloseHandle(hThread); while(1) { cout<<"main display!"<<endl; } return 0; }
我们可以看到主线程(main 函数)和我们自己的线程(Fun 函数)是随机地交替执行的, 但是两个线程输出太快,使我们很难看清楚,我们可以使用函数
eg1:
#include <iostream> #include <windows.h> using namespace std;
DWORD WINAPI Fun(LPVOID lpParamter) {
while(1) { cout<<"Fun display!"<<endl; } }
int main() {
我们假设上面两个线程正在并发欲行,如果 selfAdd 在执行的时候,我们的目的是想让 a 编程 6,但此时 selfSub 得到了运行的机会,所以 a 变成了 0,等到 selfAdd 的到执行的机会 后,a = a+a ,但是此时 a 确是 0,并没有如我们所预期的那样的到 6,我们回到前面 eg2, 在这里,我们可以把屏幕看成是一个资源,这个资源被两个线程所共用,加入当 Fun 函数 输出了 Fun display!后,将要输出 endl(也就是清空缓冲区并换行,在这里我们可以不用理 解什么事缓冲区),但此时 main 函数确得到了运行的机会,此时 Fun 函数还没有来得及输 出换行就把 CPU 让给了 main 函数,而这时 main 函数就直接在 Fun display!后输出 main dis play!,至于为 什么有的时候程序 会连续输出两个 换行,读者可以采 用同样的分析方 法来 分析,在这里我就不多讲了,留给读者自己思考了。 那么为什么我们把 eg2 改成 eg3 就可以正确的运行呢?原因在于,多个线程虽然是并发运行 的,但是有一些操作是必须一气呵成的,不允许打断的,所以我们看到 eg2 和 eg3 的运行结 果是不一样的。
eg5:
#include <iostream> #include <windows.h> using namespace std; HANDLE hMutex; DWORD WINAPI Fun(LPVOID lpParamter) {
while(1) { WaitForSingleObject(hMutex, INFINITE); cout<<"Fun display!"<<endl; Sleep(1000); ReleaseMutex(hMutex);
BOOL bInitialOwner,
// initial owner
LPCTSTR lpName
// object name
); 该函数用于创造一个独占资源,第一个参数我们没有使用,可以设为 NULL ,第二个参数指 定该资源初始是否归属创建它的进程,第三个参数指定资源的名称。
HANDLE hMutex = CreateMutex(NULL,TRUE,"screen"); 这条语句创造了一个名为 screen 并且归属于创建它的进程的资源