PV操作
PV操作:
P操作:passeren,通过,理解为申请资源
V操作:vrijgeven,释放,理解为释放资源
P操作定义如下:
1.sem减1。
2.若sem>=0,则P操作返回,该线程可以”通过“并继续执行。
3.若sem<0,则该线程被阻塞,进入操作系统的阻塞队列。
V操作定义如下:
1.sem加1。
2.若sem>0,则V操作返回,该线程继续执行。
3.若sem<=0,则从阻塞队列中唤醒一个阻塞在该信号量上的线程,然后再返回原线程(调用V操作的线程)继续执行。
多线程经典案例:
生产者消费者问题
include<windows.h>
#include<queue>
#include<process.h>
using namespace std;
//用EVENT解决生产者消费者问题
//有一个仓库
queue<int>store;
int StoreSize = 3;//仓库可以放3个货物
int ID = 1;//货物起始ID
//定义一个随机数组,模拟随即生产速度
int arr1[10] = { 2,1,4,0,3,4,6,1,9,0 };
int arr2[10] = { 1,1,4,8,3,5,6,1,2,0 };
HANDLE hEvent1 = INVALID_HANDLE_VALUE;//有货物时通知消费者取货
HANDLE hEvent2 = INVALID_HANDLE_VALUE;//仓库为空位时通知生产者开始生产
//生产者
void ProducerThread(LPVOID param);
//消费者
void ConsumerThread(LPVOID param);
int main()
{
hEvent1 = CreateEvent(NULL, TRUE, TRUE, L"事件对象1");//需要先开始生产
hEvent2 = CreateEvent(NULL, TRUE, FALSE, L"事件对象2");//一开始仓库是空的没货取
uintptr_t t1 =_beginthread(ProducerThread,0,NULL);
uintptr_t t2= _beginthread(ConsumerThread, 0, NULL);
//无限等待两个线程运行结束
HANDLE hArr[] = { (HANDLE)t1 ,(HANDLE)t2 };
WaitForMultipleObjects(2, hArr, TRUE, INFINITE);
CloseHandle(hEvent1);
CloseHandle(hEvent2);
return 0;
}
//生产者
void ProducerThread(LPVOID param)
{
while (TRUE)
{
//看Event是否允许生产,不允许无限等待
WaitForSingleObject(hEvent1,INFINITE);
if (store.size() < StoreSize)//有空位才生产
{
int id = ID++;//货物ID号
printf("生产产品:%d\n",id);
store.push(id);//把货物放到仓库中
Sleep(arr1[id%10]*1000);//生产速度不确定
}
else //仓库满了,需要停止生产
{
ResetEvent(hEvent1);
printf("仓库已满!\n");
}
//仓库有货物,可以通知消费者取货
if (store.size() > 0)
{
SetEvent(hEvent2);//让消费者的事件对象为有信号
}
}
}
//消费者
void ConsumerThread(LPVOID param)
{
while (TRUE)
{
//看Event是否允许生产,不允许无限等待
WaitForSingleObject(hEvent2, INFINITE);
if (store.size() > 0)
{
int id = store.front(); //获取第一个货物的ID,队列先进先出
store.pop(); //取出货物,腾出空间
printf(" 取出货物:%d\n", id);
Sleep(arr2[id % 10] * 1000); //生产速度不确定
}
else//仓库空了
{
ResetEvent(hEvent2);//设为无信号,不能取货物
printf("仓库空了!\n");
}
if (store.size() < 3)//说明仓库没满,可以继续生产
{
SetEvent(hEvent1);
}
}
}