原文1:https://blog.csdn.net/gengshenghong/article/details/6945216
原文2:https://www.cnblogs.com/Tony100K/p/11758936.html
Ref:
MSDN: http://msdn.microsoft.com/zh-cn/library/y6h8hye8(v=VS.100)
一、win32多线程的创建
Win32多线程的创建方法主要有:
(1)CreateThread()
(2)_beginthread()&&_beginthreadex()
(3)AfxBeginThread()
(4)CWinThread类
1、CreateThread()
百度百科:http://baike.baidu.com/view/1191444.htm
函数原型:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
}
头文件:Windows.h
CreateThread是Win32提供的创建线程的最基础的API,用于在主线程上创建一个线程。返回一个HANDLE句柄(内核对象)。
参数简要说明:
lpThreadAttributes:线程属性,用于设置线程的属性,NULL表示使用默认的设置。dwStackSize:线程堆栈大小,使用0采用默认设置,windows会根据需要动态增加堆栈大小。lpStartAddress:指向线程函数的指针。lpParameter:向线程函数传递的参数。dwCreationFlags:线程标志,CREATE_SUSPENDED表示创建一个挂起的线程,0表示创建后立即激活线程。lpThreadId,先线程的ID(输出参数)。
创建线程的代码:
#include "stdafx.h"
#include <Windows.h>
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
printf("sub thread started\n");
printf("sub thread finished\n");
return 0;
}
int main(int argc, char* argv[])
{
DWORD threadID;
HANDLE hThread;
hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创建线程
return 0;
}
如果直接使用上面的代码,那么很可能没有任何输出,这是由于主线程创建了子线程后主线程继续向下运行,子线程还没来得及执行里面的代码主线程可能就结束了。这就需要另一个API来进行同步:WaitForSingleObject()。
与之对应的还有WaitForMultipleObjects,用于同步一组内核对象。(参考http://msdn.microsoft.com/zh-cn/site/ms686360获取所有的同步函数(Synchronization Functions)的使用。
WaitForSingleObject原型:DWORD WINAPI WaitForSingleObject(__in HANDLE hHandle, __in DWORD dwMilliseconds);其中,第一个参数是要等待的内核对象的句柄,第二个参数是设置等待超时时间,可以设置为INFINITE,表示一直等待直到有信号触发。
在内核对象使用完毕后,一般需要关闭,使用CloseHandle()函数,参数为内核对象句柄。
所以,以下是一个最基本的使用CreateThread的例子:
#include "stdafx.h"
#include <Windows.h>
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
printf("sub thread started\n");
// TODO: Add your thread code here.
printf("sub thread finished\n");
return 0;
}
int main(int argc, char* argv[])
{
DWORD threadID;
HANDLE hThread;
hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 创建线程
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread); // 关闭内核对象
return 0;
}
2、_beginthread()&&_beginthreadex()
百度百科:http://baike.baidu.com/view/3029167.htm
MSDN:http://msdn.microsoft.com/zh-cn/library/kdzttdcb.aspx
函数原型:
uintptr_t _beginthread( // NATIVE CODE
void( __cdecl *start_address )( void * ),
unsigned stack_size,
void *arglist
);
头文件:process.h
参数说明:第一个参数是线程函数的指针,第二个参数是堆栈大小,第三个参数是要传递给线程函数的参数列表。返回值也是线程句柄(关于更多说明,参考MSDN)。
同样,对于_beginthread()的同步,和CreateThread一样可以使用WaitForSingleObject函数,CloseHandle()关闭内核对象。另外,_beginthread()的线程函数是无返回值类型的,可以使用_endthread()在线程函数中结束线程。
下面是一个使用_beginthread()的基本的例子:
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
void __cdecl ThreadProc(void *para)
{
printf("sub thread started\n");
// TODO: Add your thread code here.
printf("sub thread finished\n");
_endthread(); // 可以省略,隐含会调用。
}
int main(int argc, char* argv[])
{
HANDLE hThread = (HANDLE)_beginthread(ThreadProc, 0, NULL);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
}
另外,还有一个函数_beginthreadex(),可以简单的认为_beginthread()为其简化版,所以更多的时候是使用更简单的_beginthread()了。
说明:在MSDN中可以看到一句很重要的提示,内容为“For an executable file linked with Libcmt.lib, do not call the Win32 ExitThread API; this prevents the run-time system from reclaiming allocated resources. _endthread and _endthreadex reclaim allocated thread resources and then call ExitThread.”,简单翻译就是说,对于链接Libcmt.lib的可执行程序,不要使用Win32的线程退出函数(ExitThread),这会阻止运行时系统回收分配的资源,应该使用_endthread,它能回收分配的线程资源然后调用ExitThread。这个问题看似没有提到CreateThread(),但是其实有关,这就是经常看到有些资料上坚决的说到”不要使用CreateThread创建线程,否则会内存泄漏“的来源了。
问题引出:CreateThread的内存泄漏问题(CreateThread和_beginthread的区别)
Related Topics:http://wenku.baidu.com/view/adede4ec4afe04a1b071dea4.html http://www.cnblogs.com/whiteyun/archive/2011/06/02/2067742.html ....
(1) _beginthread也是通过CreateThread来创建线程的,只是_beginthread对其进行了一些封装,将相关”资源“通过线程的本地存储(TLS)传递给了线程函数的参数,然后在调用_endthread的时候,会将这些保存的资源进行释放。
(2) 并不是所有的使用CreateThread的情况都会有内存泄漏。看了很多人的文章,只有http://wenku.baidu.com/view/adede4ec4afe04a1b071dea4.html的分析是最清晰的,我已经转到http://dl.dbank.com/c03ljl2iud了,可下载查看(版权归原作者所有)。
总之,建议是使用_beginthread取代CreateThread来创建线程。
3、AfxBeginThread():
很显然,这是MFC中的Afx系列函数,一个在MFC中创建线程的全局函数。由于现在也不怎么用MFC了,这里就不多说了。
4、CWinThread类:
很显然,是MFC中创建线程的类,同上,不多说了。
5、补充内容
关于WaitForMultipleObjects在_beginthread无法使用的问题
问题:使用_beginthread创建多个线程,无法使用WaitForMultipleObjects来进行同步。
这个问题可以用下面的例子来测试:
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
void __cdecl ThreadProc(void *para)
{
printf("sub thread started\n");
// TODO: Add your thread code here.
printf("sub thread finished\n");
_endthread(); // 可以省略,隐含会调用。
}
int main(int argc, char* argv[])
{
DWORD threadID;
HANDLE hThread[10];
for(int i =0;i<10;i++)
hThread[i] = (HANDLE)_beginthread(ThreadProc,0,NULL);
WaitForMultipleObjects(10, hThread,TRUE,INFINITE); //无法同步所有线程!
for(int i = 0;i<10;i++) {
CloseHandle(hThread);
}
}
期望的结果是程序能输出10次的线程创建结束的消息,但是实际运行发现,无法达到这么多次数。为何?这是因为WaitForMultipleObjects在这里无法正常工作。原因是:
_endthread()在结束线程的时候,会自动调用CloseHandle关闭内核对象。这就容易解释了,如果提前关闭了内核对象,WaitForMultipleObjects会返回错误。那么有没有专门用于_beginthread创建的线程的同步方法呢,就我目前所知,好象是没有的!要解决这里的问题,可以分别调用WaitForSingleObject来同步,当然,使用其他一些变相的方法也是可以的,另外,上面的CloseHandle当然就可以不用再调用了。
总结:看来_beginthread也不是那么好用。:)
二、创建执行挂起终止
- CreateThread(NULL, 0, FunOne, (void*)&input, CREATE_SUSPENDED, NULL);
- 安全属性 栈大小 线程函数 参数指针 附加标志 ID号(32位int指针)
- 附加标志为0 创建即可执行
- 附加标志为CREATE_SUSPENDED 创建就要挂起
- ResumeThread(句柄) 挂起计数器-1,为0则进行
- SuspendThread(句柄) 挂起计数器+1
- TerminateThread(hand1, 1) 第二个参数为exitcode
- 调用SetThreadPriority函数设置线程的相对优先级,例如
Bool SetThreadPriority (HANDLE hPriority , int nPriority)
参数hPriority 指向待设置的线程句柄 - nPriority 是线程的相对优先级,可以是以下的值:
空闲:THREAD - PRIORITY- IDLE 15
最低线程:THREAD - PRIORITY- LOWEST 2
低于正常线程:THREAD - PRIORITY- BELOW- NORMAL 1
正常线程:THREAD - PRIORITY- NORMAL 0
高于正常线程:THREAD - PRIORITY- ABOVE – NORMAL -1
最高线程:THREAD - PRIORITY- HIGHEST -2
关键时间:THREAD - PRIORITY- TIME – CRITICAL -15 -
挂起与恢复函数原型
DWORD SuspendThread(HANDLE hThread);
挂起指定的线程(慎用,不处理同步对象)
如果函数执行成功,则线程的执行被终止
每次调用SuspendThread() 函数,线程将挂起计数器的值增1DWORD ResumeThread(HANDLE hThread);
结束线程的挂起状态来执行这个线程
每次调用ResumeThread() 函数,线程将挂起计数器的值减1
若挂起计数器的值为0,则不会再减
#include "stdio.h"
#include <windows.h>
#include <iostream>
using namespace std;
//简单的多线程创建、执行、挂起、终止的程序例子。
DWORD WINAPI FunOne(LPVOID param) {
while (true)
{
Sleep(1000);
cout << "hello! ";
//cout<<"hello! "<<*((int*)param);
}
return 0;
}
DWORD WINAPI FunTwo(LPVOID param) {
while (true)
{
Sleep(1000);
cout << "world! ";
}
return 0;
}
//注意创建线程函数的第五个参数的运用。
//输入1和2数字,可以控制线程的启动和终止。
//注意连续输入1和2数字线程的运行情况。
//线程的终止函数。
int main(int argc, char* argv[])
{
int input = 0;
//创建线程。这里第四个参数值设为NULL也可以,因为线程函数里没有使用输入参数。
HANDLE hand1 = CreateThread(NULL, 0, FunOne, (void*)&input, CREATE_SUSPENDED, NULL);
HANDLE hand2 = CreateThread(NULL, 0, FunTwo, (void*)&input, CREATE_SUSPENDED, NULL);
while (true) {
cin >> input;
if (input == 1)
{
//恢复线程
ResumeThread(hand1);
ResumeThread(hand2);
}
if (input == 2)
{
//挂起线程
SuspendThread(hand1);
SuspendThread(hand2);
}
if (input == 0)
{
//终止线程
TerminateThread(hand1, 1);
TerminateThread(hand2, 1);
}
if (input == 9)
return 0;
};
return 0;
}
三、利用全局变量实现同步
这样做可能会有一个问题,主线程结束时其他线程也就跟着结束了
- 全局变量
进程中的所有线程均可以访问所有的全局变量,因而全局变量成为Win32多线程通信的最简单方式。
int var; //全局变量
UINT ThreadFunction ( LPVOID pParam {
while (var)
{
…… //线程处理
}
return 0; }
var是一个全局变量,任何线程均可以访问和修改。线程间可以利用此特性达到线程同步的目的。
#include "stdio.h"
#include <windows.h>
#include <iostream>
using namespace std;
//使用全局变量同步线程的例子。
//全局变量。
int globalvar = false;
DWORD WINAPI ThreadFunc(LPVOID pParam)
{
cout << " ThreadFunc " << endl;
Sleep(100);
//修改全局变量的值。
globalvar = true;
return 0;
}
DWORD WINAPI ThreadFunc1(LPVOID pParam)
{
while (1)
cout << " ThreadFunc111 " << endl;
return 0;
}
DWORD WINAPI ThreadFunc2(LPVOID pParam)
{
while (1)
cout << " ThreadFunc222 " << endl;
return 0;
}
//这种方式可能存在一些问题。
int main()
{
HANDLE hthread1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL);
HANDLE hthread2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL);
HANDLE hthread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
if (!hthread)
{
cout << "Thread Create Error ! " << endl;
CloseHandle(hthread);
}
bool b =SetThreadPriority(hthread,15);
cout<<GetThreadPriority(hthread1)<<endl;
cout<<GetThreadPriority(hthread2)<<endl;
cout<<GetThreadPriority(hthread)<<endl;
//循环判断全局变量的值。
while (!globalvar)
cout << "Thread while" << endl;
cout << "Thread exit" << endl;
return 0;
}
四、利用事件实现同步
-
事件是WIN32提供的最灵活的线程间同步方式。
事件存在两种状态:
激发状态(signaled or true)
未激发状态(unsignal or false)
事件可分为两类:
手动设置:这种对象只能用程序来手动设置,在需要该事件或者事件发生时,采用SetEvent及ResetEvent来进行设置。
SetEvent只有一个参数,该参数指定了事件对象的句柄值,若事件成功激发,返回TRUE;
ResetEvent函数将事件对象恢复到最初的非激发状态,只有一个参数,成功后返回真
自动恢复:一旦事件发生并被处理后,自动恢复到没有事件状态,不需要再次设置。 - CreateEvent(NULL, FALSE, FALSE, NULL);
- 第一个参数还是安全,默认为NULL,二参代表事件类型,true为手动清除信号,false为自动清除
- 三参:事件的初始状态 四参:事件的名称
- setEvent(句柄)
- WaitForSingleObject(evRead, INFINITE);等待某个事件
WaitForSingleObject (evFinish, INFINITE)
参数1:等待对象
参数2:等待时间
返回值:WAIT_OBJECT_0(激发)
WAIT_TIMEOUT(超时)
WAIT_FAILED(错误) - WaitForMultipleObjects(2 ,evFin ,TRUE ,INFINITE)
参数1:等待的句柄数
参数2:等待的句柄数组
参数3:确定是否等待所有句柄激发后才返回
参数4:等待时间
返回值: WAIT_OBJECT_I(激发事件在句柄数组中的索引) -
例子:有三个线程
主线程、读线程ReadThread、写线程WriteThread
读线程ReadThread必须在写线程WriteThread 的写操作完成之后才能进行读操作
主线程必须在读线程ReadThread 的读操作完成后才结束
定义两个事件对象evRead,evFinish
evRead由写线程WriteThread用于通知读线程ReadThread 进行读操作
evFinish由读线程ReadThread用于通知主线程读操作已经结束
#include "stdio.h"
#include <windows.h>
#include <iostream>
using namespace std;
//**使用事件机制同步线程的例子。
//两个事件。
HANDLE evRead, evFin;
HANDLE evWrite;
void ReadThread(LPVOID param)
{
//等待读事件。
WaitForSingleObject(evRead, INFINITE);
cout << "Reading" << endl;
//ResetEvent(evRead);//evRead为手动恢复类型时打开
SetEvent(evWrite);
WaitForSingleObject(evRead, INFINITE);
cout << "Reading11111" << endl;
//激活结束事件。
SetEvent(evFin);
}
void WriteThread(LPVOID param)
{
cout << "Writing" << endl;
//激活读事件。
SetEvent(evRead);
WaitForSingleObject(evWrite, INFINITE);
cout << "Writing11111" << endl;
SetEvent(evRead);
}
int main(int argc, char* argv[])
{
//创建两个事件,注意事件参数的含义。
evRead = CreateEvent(NULL, FALSE, FALSE, NULL);
evFin = CreateEvent(NULL, FALSE, FALSE, NULL);
evWrite = CreateEvent(NULL, FALSE, FALSE, NULL);
//evRead = CreateEvent (NULL ,TRUE ,FALSE ,NULL) ;//修改第二个参数为TRUE
//evFin = CreateEvent (NULL ,TRUE ,FALSE ,NULL) ;//修改第二个参数为TRUE
//evWrite = CreateEvent (NULL ,TRUE ,FALSE ,NULL) ;//修改第二个参数为TRUE
_beginthread(ReadThread, 0, NULL);
_beginthread(WriteThread, 0, NULL);
//等待结束事件。
WaitForSingleObject(evFin, INFINITE);
cout << "The Program is End" << endl;
return 0;
}
五、临界区
- 防止多个线程同时执行一个特定代码段的机制
适用于多个线程操作之间没有先后顺序,但要求互斥的同步
多个线程访问同一个临界区的原则:
一次最多只能一个线程停留在临界区内
不能让一个线程无限地停留在临界区内,否则其它线程将不能进入该临界区
定义临界区变量的方法如下:
CRITICAL_SECTION gCriticalSection;
通常情况下,CRITICAL_SECTION结构体应该被定义为全局变量,便于进程中的所有线程可以方便地按照变量名来引用该结构体。 - 初始化临界区
VOID WINAPI InitializeCriticalSection (
LPCRITICAL_SECTION lpCriticalSection );
删除临界区
VOID WINAPI DeleteCriticalSection (
LPCRITICAL_SECTION lpCriticalSection );
进入临界区
VOID WINAPI EnterCriticalSection (
LPCRITICAL_SECTION lpCriticalSection );
执行该语句时,程序会判断cs对象是否已被锁定,若没锁定则线程进入临界区,并将cs置为锁定状态;否则,线程线程被阻塞以等待cs解锁。
离开临界区
VOID WINAPI LeaveCriticalSection (
LPCRITICAL_SECTION lpCriticalSection );
线程执行该语句后,程序自动将cs解锁,并唤醒等待cs解锁的线程 - 使用临界区编程的一般方法是:
void WriteData()
{
EnterCriticalSection(&gCriticalSection);
//do something
LeaveCriticalSection(&gCriticalSection);
}
例子
假如一个银行系统有两个线程执行取款任务,一个使用存折在柜台取款,一个使用银行卡在ATM取款。若不加控制,很可能账户余额不足两次取款的总额,但还可以把钱取走。
#include "stdio.h"
#include <windows.h>
#include <iostream>
#include <process.h>
#include <iostream>
#include <fstream>
using namespace std;
//**使用临界区机制同步线程。
int total = 100;
HANDLE evFin[2];
CRITICAL_SECTION cs;//临界区。
//可以去掉临界区机制,查看是否出现错误。(需要辅助sleep函数)
void WithdrawThread1(LPVOID param)
{
EnterCriticalSection(&cs);//进入临界区
if (total - 90 >= 0)
{//Sleep(100);
total -= 90;
cout << "You withdraw 90" << endl;
}
else
cout << "You do not have that much money" << endl;
LeaveCriticalSection(&cs);//退出临界区
SetEvent(evFin[0]);
}
void WithdrawThread2(LPVOID param)
{
EnterCriticalSection(&cs);//进入临界区
if (total - 20 >= 0)
{
total -= 20;
cout << "You withdraw 20" << endl;
}
else
cout << "You do not have that much money" << endl;
LeaveCriticalSection(&cs);//退出临界区
//LeaveCriticalSection(&cs) ;
SetEvent(evFin[1]);
}
int main(int argc, char* argv[])
{
evFin[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
evFin[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
InitializeCriticalSection(&cs);//初始化临界区。
_beginthread(WithdrawThread1, 0, NULL);//创建线程顺序影响执行的结果。
_beginthread(WithdrawThread2, 0, NULL);
//_beginthread(WithdrawThread1 , 0 , NULL) ;
int id = WaitForMultipleObjects(2, evFin, TRUE, INFINITE);//等待两个事件都激活。
cout << "句柄数组中的索引:" << id << endl;
DeleteCriticalSection(&cs);//删除临界区
cout << total << endl;
return 0;
}
六、互斥量
- 通常用于协调多个线程或进程的活动,通过对资源“锁定”和“取消锁定”,来控制对共享资源的访问。
当一个互斥量被一个线程锁定了,其他试图对其加锁的线程就会被阻塞;当对互斥量加锁的线程解除锁定后,则被阻塞的线程中的一个会得到互斥量。
互斥量的作用是保证每次只能有一个线程获得互斥量
使用CreateMutex函数创建:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName
);
安全属性 是否手动清除(true为手动) 名称 - 相关的API:
CreateMutex 创建一个互斥对象,返回对象句柄;
OpenMutex 打开并返回一个已存在的互斥对象的句柄,使之后续访问;
ReleaseMutex 释放对互斥对象的占用,使之成为可用;
使用互斥量的一般方法是:
void Writedata()
{
WaitForSingleObject(hMutex,…);
...//do something
ReleaseMutex(hMutex);
}
#include "stdio.h"
#include <windows.h>
#include <iostream>
#include <process.h>
#include <iostream>
#include <fstream>
using namespace std;
//**互斥量的使用方法。
#define THREAD_INSTANCE_NUMBER 3
LONG g_fResourceInUse = FALSE;
LONG g_lCounter = 0;
DWORD ThreadProc(void* pData) {
int ThreadNumberTemp = (*(int*)pData);
HANDLE hMutex;
if ((hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "Mutex.Test")) == NULL) {
cout << "Open Mutex error!" << endl;
}
//cout << "ThreadProc is running hMutexxxxxxx!!" << ThreadNumberTemp <<endl;
WaitForSingleObject(hMutex, INFINITE);//获取互斥量。
cout << "ThreadProc is running!!" << ThreadNumberTemp << endl;
cout << "ThreadProc gets the mutex-" << ThreadNumberTemp << endl;
ReleaseMutex(hMutex);//释放互斥量。
CloseHandle(hMutex);
return 0;
}
int main(int argc, char* argv[])
{
int i;
DWORD ID[THREAD_INSTANCE_NUMBER];
HANDLE h[THREAD_INSTANCE_NUMBER];
HANDLE hMutex;
if ((hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "Mutex.Test")) == NULL) {
if ((hMutex = CreateMutex(NULL, FALSE, "Mutex.Test")) == NULL) //注意第二个参数,当前线程是否拥有创建的锁
{
cout << "Create Mutex error!" << endl;
return 0;
}
}
//ReleaseMutex(hMutex); //CreateMutex函数第二参数为TRUE时打开
//获取信号量的位置不同,将产生不同的结果。
//WaitForSingleObject(hMutex,INFINITE);
for (i = 0; i < THREAD_INSTANCE_NUMBER; i++)
{
WaitForSingleObject(hMutex, INFINITE);//获取互斥量。本线程可重复获取,但解锁时需释放相同的次数。
h[i] = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)ThreadProc,
(void*)&ID[i],
0,
&(ID[i]));
//WaitForSingleObject(hMutex,INFINITE);//演示重复获取互斥量
if (h[i] == NULL)
cout << "CreateThread error" << ID[i] << endl;
else
cout << "CreateThread: " << ID[i] << endl;
ReleaseMutex(hMutex);
//Sleep(1000);
}
//ReleaseMutex(hMutex);//ReleaseMutex(hMutex);ReleaseMutex(hMutex);//演示释放重复获取的互斥量
WaitForMultipleObjects(THREAD_INSTANCE_NUMBER, h, TRUE, INFINITE);
cout << "Close the Mutex Handle! " << endl;
CloseHandle(hMutex);
return 0;
}
七、信号量
- 信号量是一个核心对象,拥有一个计数器,可用来管理大量有限的系统资源
当计数值大于零时,信号量为有信号状态
当计数值为零时,信号量处于无信号状态
创建信号量
HANDLE CreateSemaphore (PSECURITY_ATTRIBUTE psa,
LONG lInitialCount, LONG lMaximumCount, PCTSTR pszName);
安全属性 初始数量 最大数量 信号量名称 - 释放信号量
BOOL WINAPI ReleaseSemaphore(HANDLE hSemaphore,
LONG lReleaseCount, //信号量的当前资源数增加lReleaseCount
LPLONG lpPreviousCount);
打开信号量
HANDLE OpenSemaphore (DWORD fdwAccess,
BOOL bInherithandle, PCTSTR pszName );
// exa7.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;
//**使用信号量机制同步线程。
#define THREAD_INSTANCE_NUMBER 3
DWORD foo(void * pData) {
int ThreadNumberTemp = (*(int*) pData);
HANDLE hSemaphore;
if ((hSemaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Semaphore.Test")) == NULL) {
cout << "Open Semaphore error!" << endl;
}
WaitForSingleObject(hSemaphore,INFINITE);//获取信号量。
cout << "foo is running!!!" << ThreadNumberTemp << endl;
cout << "foo gets the semaphore-" << ThreadNumberTemp<< endl;
ReleaseSemaphore(hSemaphore, 1, NULL);//释放一个单位的信号量
CloseHandle(hSemaphore);
return 0;
}
int main(int argc, char* argv[])
{
int i;
DWORD ThreadID[THREAD_INSTANCE_NUMBER];
HANDLE hThread[THREAD_INSTANCE_NUMBER];
HANDLE hSemaphore;
if ((hSemaphore = CreateSemaphore(NULL,1,1, "Semaphore.Test")) == NULL ) {
cout << "Create Semaphore error!" << endl;
return 0;
}
//与互斥量一样,这里获取信号量的位置不同,会产生不同的结果。
for (i=0;i<THREAD_INSTANCE_NUMBER;i++)
{
WaitForSingleObject(hSemaphore,INFINITE);//获取信号量。不可重入。
hThread[i] = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE) foo,
(void *)&ThreadID[i],
0,
&(ThreadID[i]));
if (hThread[i] == NULL)
cout << "CreateThread error" << ThreadID[i] << endl;
else
cout << "CreateThread: " << ThreadID[i] << endl;
ReleaseSemaphore(hSemaphore, 1, NULL);
}
WaitForMultipleObjects(THREAD_INSTANCE_NUMBER,hThread,TRUE,INFINITE);
cout << "Close the Semaphore Handle! " << endl;
CloseHandle(hSemaphore);
return 0;
}
来源:CSDN
作者:fengruoying93
链接:https://blog.csdn.net/fengruoying93/article/details/103945658