用信号量实现线程同步与互斥
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
LONG lInitialCount, // initial count
LONG lMaximumCount, // maximum count
LPCTSTR lpName // object name);
各参数含义:
lpSemaphoreAttributes:指定一个SECURITY_ATTRIBUTES结构,或传递零值。该参数定义了信号机的安全特性。
dwMilliseconds是时间间隔。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。如果事件是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT。;
}
else //i为奇数时,创建B组线程
{
hThreads[i]=CreateThread(NULL,0,Process_B,NULL,0,&BID[j]);
j++;
if (hThreads[i]==NULL) return -1;
}
}
while(g_continue){
if(getchar()){ //按回车后终止程序运行
lpThreadId:该参数返回所创建线程的ID。
如果创建成功则返回线程的句柄,否则返回NULL。
例如:
for (int i=0;i<PRODUCERS_COUNT;++i){
hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);
g_continue = false;
}
}
return 0;
}
DWORD WINAPI Process_A(LPVOID lpPara)
{
/*
P(S1);
num1++;
if(num1==1) then P(mutex);
V(S1);
读文件P;
P(S1);
num1--;
if(num1==0) then V(mutex);
9、检测信号状态
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds)
参数含义:
hHandle:是一个事件的句柄。参在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。
4、终止线程
VOID ExitThread(DWORD dwExitCode);
该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。
5、创建互斥体
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTESlpMutexAttributes,
//同组用于互斥访问文件,本不应该用这个互斥信号量,只是为了能看清楚输出结果。
HANDLE g_hMutexRead;
HANDLE g_hMutex; //用于A,B两组互斥访问文件
HANDLE g_hA; //用于A组进程互斥访问计数器
HANDLE g_hB; //用于B组进程互斥访问计数器
void read();//模拟读
例如,电脑有两个COM PORT,所以只允许两个计数值同时使用COM PORT,因此,hSema = CreateSemaphore(NULL, 2, 2, "MySema")
8、释放信号量
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
函数作用:在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄。
各参数含义:
lpThreadAttributes:指向一个SECURITY_ATTRIBUTES结构的指针,该结构决定了线程的安全属性,一般置为NULL;
6、释放互斥体
BOOL WinAPI ReleaseMutex(HANDLE hMutex);
hMutex:要释放的互斥体句柄。返回值0代表失败;非0代表成功。
7、创建信号量
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD
//总的线程数
const unsigned short THREADS_COUNT = A_COUNT+B_COUNT;
HANDLE hThreads[THREADS_COUNT]; //各线程的handle
DWORD AID[A_COUNT];
DWORD BID[B_COUNT];
//创建THREADS_COUNT个线程,读或写线程间隔开
lpName:指定互斥体对象的名字。如已经存在拥有这个名字的一个事件,则打开现有的已命名互斥体
例如,
HANDLE m_hMutex = CreateMutex(NULL, FALSE, "Sample07");
//检查错误代码
if (GetLastError() == ERROR_ALREADY_EXISTS) {
LPLONG lpPreviousCount);
各参数含义:
hSemaphore:信号量句柄
lpReleaseCount:表示要增加的数值,
lpPreviousCount:用于返回之前的计算值,如果不需要可以设置为NULL。
比如我们要控制到服务器的连接数不超过10个,可以创建一个Semaphore,初值为10,每当要连接到服务器时,使用WaitForSingleObject请求Semaphore,当成功返回后再尝试连接到服务器,当连接失败或连接使用完后释放时,调用ReleaseSemaphore增加Semaphore计数值。
lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数;
dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;
if (hThreads[i]==NULL) return -1;
}
2、挂起线程
DWORD SuspendThread(HANDLE hThread);
该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。
3、唤醒线程
DWORD ResumeThread(HANDLE hThread);
该函数用于结束线程的挂起状态,执行线程。
{
P(S1);
num1++;
if(num1==1) then P(mutex);
V(S1);
读文件P;
P(S1);
num1--;
if(num1==0) then V(mutex);
V(S1);
}
Process_B()
{
P(S2);
num2++;
if(num2==1) then P(mutex);
V(S2);
//如果已有互斥量存在则释放句柄并复位互斥量
CloseHandle(m_hMutex);
m_hMutex = NULL;
//程序退出
return FALSE;
}
互斥体可用来实现线程的同步或互斥。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。
一旦不再需要,注意必须用CloseHandle函数将互斥体句柄关闭。进程中止前,一定要释放互斥体,如不慎未采取这个措施,就会将这个互斥体标记为废弃,并自动释放所有权。共享这个互斥体的其他应用程序也许仍然能够用它,但会接收到一个废弃状态信息,指出上一个所有进程未能正常关闭。
二、实例
问题描述:有一个文件P被多个进程共享,现在把这些进程分成A、B两组,规定同组进程可以同时读文件P,但当一组进程在读文件P时,不允许另外一组去读文件。用信号量模拟两组进程的读操作。
伪代码:
Semaphore S1=1,S2=1,mutex=1;
Int num1=0,num2=0;
Process_A()
读文件P;
P(S2);
num2--;
if(num2==0) then V(mutex);
V(S2);
}
实现代码:
#include <windows.h>
#include <iostream>
using namespace std;
bool g_continue = true; //控制程序结束
int g_Anum=0,g_Bnum=0;
DWORD WINAPI Process_A(LPVOID); //A组线程
DWORD WINAPI Process_B(LPVOID); //B组线程
int main()
{
//创建互斥访问文件的信号
g_hMutexRead = CreateMutex(NULL,FALSE,NULL);
g_hMutex = CreateMutex(NULL,FALSE,NULL);
用信号量实现线程同步与互斥
一、相关Win32 API函数
1、创建线程
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
返回值含义:
WAIT_ABANDONED 0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。
WAIT_OBJECT_0 0x00000000:核心对象已被激活
WAIT_TIMEOUT 0x00000102:等待超时
WAIT_FAILED 0xFFFFFFFF:出现错误,可通过GetLastError得到错误代码
V(S1);
*/
WaitForSingleObject(g_hA,INFINITE);
g_Anum++;
if(g_Anum==1)
{
WaitForSingleObject(g_hMutex,INFINITE);
lInitialCount Long,设置信号量的初始值。可设置零到lMaximumCount之间的一个值。
lMaximumCount Long,设置信号量的最大计数
lpName String,指定信号量对象的名称。如果已经存在拥有这个名字的一个信号量,就直接打开现成的信号量。NULL表示创建匿名信号量。
int k=0,j=0;
for(int i=0;i<THREADS_COUNT;++i)
{
if(i%2==0) //i为偶数时,创建A组线程
{Leabharlann Baidu
hThreads[i]=CreateThread(NULL,0,Process_A,NULL,0,&AID[k]);
k++;
if (hThreads[i]==NULL) return -1;
g_hA = CreateMutex(NULL,FALSE,NULL);
g_hB = CreateMutex(NULL,FALSE,NULL);
const unsigned short A_COUNT = 3; //A组线程的个数
const unsigned short B_COUNT = 2; //B组线程的个数
BOOLbInitialOwner,
LPCTSTRlpName);
各参数含义:
lpMutexAttributes:指向一个SECURITY_ATTRIBUTES结构的指针,这个结构决定互斥体句柄是否被子进程继承。
bInitialOwner:布尔类型,决定互斥体的创建者是否为拥有者。创建进程希望立即拥有互斥体,则设为TRUE,否则设为FALSE。
dwStackSize:指定了线程的堆栈深度,一般都设置为0;
lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc是线程函数名;函数名称没有限制,但是必须以下列形式声明:DWORD WINAPIThreadProc(PVOID pParam);
LONG lMaximumCount, // maximum count
LPCTSTR lpName // object name);
各参数含义:
lpSemaphoreAttributes:指定一个SECURITY_ATTRIBUTES结构,或传递零值。该参数定义了信号机的安全特性。
dwMilliseconds是时间间隔。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。如果事件是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT。;
}
else //i为奇数时,创建B组线程
{
hThreads[i]=CreateThread(NULL,0,Process_B,NULL,0,&BID[j]);
j++;
if (hThreads[i]==NULL) return -1;
}
}
while(g_continue){
if(getchar()){ //按回车后终止程序运行
lpThreadId:该参数返回所创建线程的ID。
如果创建成功则返回线程的句柄,否则返回NULL。
例如:
for (int i=0;i<PRODUCERS_COUNT;++i){
hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);
g_continue = false;
}
}
return 0;
}
DWORD WINAPI Process_A(LPVOID lpPara)
{
/*
P(S1);
num1++;
if(num1==1) then P(mutex);
V(S1);
读文件P;
P(S1);
num1--;
if(num1==0) then V(mutex);
9、检测信号状态
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds)
参数含义:
hHandle:是一个事件的句柄。参在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。
4、终止线程
VOID ExitThread(DWORD dwExitCode);
该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。
5、创建互斥体
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTESlpMutexAttributes,
//同组用于互斥访问文件,本不应该用这个互斥信号量,只是为了能看清楚输出结果。
HANDLE g_hMutexRead;
HANDLE g_hMutex; //用于A,B两组互斥访问文件
HANDLE g_hA; //用于A组进程互斥访问计数器
HANDLE g_hB; //用于B组进程互斥访问计数器
void read();//模拟读
例如,电脑有两个COM PORT,所以只允许两个计数值同时使用COM PORT,因此,hSema = CreateSemaphore(NULL, 2, 2, "MySema")
8、释放信号量
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
函数作用:在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄。
各参数含义:
lpThreadAttributes:指向一个SECURITY_ATTRIBUTES结构的指针,该结构决定了线程的安全属性,一般置为NULL;
6、释放互斥体
BOOL WinAPI ReleaseMutex(HANDLE hMutex);
hMutex:要释放的互斥体句柄。返回值0代表失败;非0代表成功。
7、创建信号量
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD
//总的线程数
const unsigned short THREADS_COUNT = A_COUNT+B_COUNT;
HANDLE hThreads[THREADS_COUNT]; //各线程的handle
DWORD AID[A_COUNT];
DWORD BID[B_COUNT];
//创建THREADS_COUNT个线程,读或写线程间隔开
lpName:指定互斥体对象的名字。如已经存在拥有这个名字的一个事件,则打开现有的已命名互斥体
例如,
HANDLE m_hMutex = CreateMutex(NULL, FALSE, "Sample07");
//检查错误代码
if (GetLastError() == ERROR_ALREADY_EXISTS) {
LPLONG lpPreviousCount);
各参数含义:
hSemaphore:信号量句柄
lpReleaseCount:表示要增加的数值,
lpPreviousCount:用于返回之前的计算值,如果不需要可以设置为NULL。
比如我们要控制到服务器的连接数不超过10个,可以创建一个Semaphore,初值为10,每当要连接到服务器时,使用WaitForSingleObject请求Semaphore,当成功返回后再尝试连接到服务器,当连接失败或连接使用完后释放时,调用ReleaseSemaphore增加Semaphore计数值。
lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数;
dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;
if (hThreads[i]==NULL) return -1;
}
2、挂起线程
DWORD SuspendThread(HANDLE hThread);
该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。
3、唤醒线程
DWORD ResumeThread(HANDLE hThread);
该函数用于结束线程的挂起状态,执行线程。
{
P(S1);
num1++;
if(num1==1) then P(mutex);
V(S1);
读文件P;
P(S1);
num1--;
if(num1==0) then V(mutex);
V(S1);
}
Process_B()
{
P(S2);
num2++;
if(num2==1) then P(mutex);
V(S2);
//如果已有互斥量存在则释放句柄并复位互斥量
CloseHandle(m_hMutex);
m_hMutex = NULL;
//程序退出
return FALSE;
}
互斥体可用来实现线程的同步或互斥。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。
一旦不再需要,注意必须用CloseHandle函数将互斥体句柄关闭。进程中止前,一定要释放互斥体,如不慎未采取这个措施,就会将这个互斥体标记为废弃,并自动释放所有权。共享这个互斥体的其他应用程序也许仍然能够用它,但会接收到一个废弃状态信息,指出上一个所有进程未能正常关闭。
二、实例
问题描述:有一个文件P被多个进程共享,现在把这些进程分成A、B两组,规定同组进程可以同时读文件P,但当一组进程在读文件P时,不允许另外一组去读文件。用信号量模拟两组进程的读操作。
伪代码:
Semaphore S1=1,S2=1,mutex=1;
Int num1=0,num2=0;
Process_A()
读文件P;
P(S2);
num2--;
if(num2==0) then V(mutex);
V(S2);
}
实现代码:
#include <windows.h>
#include <iostream>
using namespace std;
bool g_continue = true; //控制程序结束
int g_Anum=0,g_Bnum=0;
DWORD WINAPI Process_A(LPVOID); //A组线程
DWORD WINAPI Process_B(LPVOID); //B组线程
int main()
{
//创建互斥访问文件的信号
g_hMutexRead = CreateMutex(NULL,FALSE,NULL);
g_hMutex = CreateMutex(NULL,FALSE,NULL);
用信号量实现线程同步与互斥
一、相关Win32 API函数
1、创建线程
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
返回值含义:
WAIT_ABANDONED 0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。
WAIT_OBJECT_0 0x00000000:核心对象已被激活
WAIT_TIMEOUT 0x00000102:等待超时
WAIT_FAILED 0xFFFFFFFF:出现错误,可通过GetLastError得到错误代码
V(S1);
*/
WaitForSingleObject(g_hA,INFINITE);
g_Anum++;
if(g_Anum==1)
{
WaitForSingleObject(g_hMutex,INFINITE);
lInitialCount Long,设置信号量的初始值。可设置零到lMaximumCount之间的一个值。
lMaximumCount Long,设置信号量的最大计数
lpName String,指定信号量对象的名称。如果已经存在拥有这个名字的一个信号量,就直接打开现成的信号量。NULL表示创建匿名信号量。
int k=0,j=0;
for(int i=0;i<THREADS_COUNT;++i)
{
if(i%2==0) //i为偶数时,创建A组线程
{Leabharlann Baidu
hThreads[i]=CreateThread(NULL,0,Process_A,NULL,0,&AID[k]);
k++;
if (hThreads[i]==NULL) return -1;
g_hA = CreateMutex(NULL,FALSE,NULL);
g_hB = CreateMutex(NULL,FALSE,NULL);
const unsigned short A_COUNT = 3; //A组线程的个数
const unsigned short B_COUNT = 2; //B组线程的个数
BOOLbInitialOwner,
LPCTSTRlpName);
各参数含义:
lpMutexAttributes:指向一个SECURITY_ATTRIBUTES结构的指针,这个结构决定互斥体句柄是否被子进程继承。
bInitialOwner:布尔类型,决定互斥体的创建者是否为拥有者。创建进程希望立即拥有互斥体,则设为TRUE,否则设为FALSE。
dwStackSize:指定了线程的堆栈深度,一般都设置为0;
lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc是线程函数名;函数名称没有限制,但是必须以下列形式声明:DWORD WINAPIThreadProc(PVOID pParam);