一、PV原语介绍

PV原语通过操作信号量来处理进程间的同步与互斥的问题。其核心就是一段不可分割不可中断的程序。

信号量的概念1965年由著名的荷兰计算机科学家Dijkstra提出,其基本思路是用一种新的变量类型(semaphore)来记录当前可用资源的数量。有两种实现方式:1)semaphore的取值必须大于或等于0。0表示当前已没有空闲资源,而正数表示当前空闲资源的数量;2) semaphore的取值可正可负,负数的绝对值表示正在等待进入临界区的进程个数。

信号量是由操作系统来维护的,用户进程只能通过初始化和两个标准原语(P、V原语)来访问。初始化可指定一个非负整数,即空闲资源总数。

二、PV原语原理

PV操作由P操作原语和V操作原语组成(原语也叫原子操作Atomic Operation,是不可中断的过程),对信号量(注意不要和Windows中的信号量机制相混淆)进行操作,具体定义如下:

PV操作对于每一个进程来说,都只能进行一次,而且必须成对使用。在PV原语执行期间不允许有中断的发生。

P(S):

①将信号量S的值减1,即S=S-1;

②如果S>=0,则该进程继续执行;否则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。

V(S):

①将信号量S的值加1,即S=S+1;

②该进程继续执行;如果该信号的等待队列中有等待进程就唤醒一等待进程。

具体PV原语对信号量的操作可以分为三种情况:

  1. 把信号量视为一个加锁标志位,实现对一个共享变量的互斥访问。实现过程如下:

    P(mutex); // mutex的初始值为1 访问该共享数据;

    V(mutex);

    非临界区

  2. 把信号量视为是某种类型的共享资源的剩余个数,实现对一类共享资源的访问。实现过程如下:

    P(resource); // resource的初始值为该资源的个数N 使用该资源;

    V(resource);

    非临界区

  3. 把信号量作为进程间的同步工具(???)。实现过程如下:

    临界区C1;

    P(S);

    V(S);

    临界区C2;

三、实例分析

(一) 题目

桌上有一空盘,允许存放一只水果。爸爸可向盘中放苹果,也可向盘中放橘子,儿子专等吃盘中的橘子,女儿专等吃盘中的苹果。规定当盘空时一次只能放一只水果供吃者取用,请用P、V原语实现爸爸、儿子、女儿三个并发进程的同步。

(二) 过程分析

  • 先考虑同步情况即所有“等待”情况:

    第一.爸爸要等待盘子为空。

    第二.儿子要等待盘中水果是橘子。

    第三.女儿要等待盘中水果是苹果。

  • 看起来盘子好像是要作互斥处理的,但由于题目中的爸爸、儿子、女儿均只有一个,并且他们访问盘子的条件都不一样,所以他们根本不会同时去访问盘子,因此盘子也就不用作互斥处理了。

  • 先设置三个信号量,信号量Orange表示盘中有橘子,初值为0。信号量Apple表示盘中有苹果,初值为0。信号量EmptyDish表示盘子为空,初值为1。

1.爸爸

P(EmptyDish)

if (rand()%2==0)

{

放橘子

V(Orange)

}

else

{

放苹果

V(Apple)

}

2.儿子

P(Orange)

取橘子

V(EmptyDish)

3.女儿

P(Apple)

取苹果

V(EmptyDish)

(三) 代码实现



#include <iostream>
#include<windows.h>
using namespace std; DWORD WINAPI FatherThread(LPVOID); //爸爸往盘子中放橘子或苹果的线程
DWORD WINAPI DaughterThread(LPVOID); //女儿取走苹果线程
DWORD WINAPI SonThread(LPVOID); //儿子取走橘子线程 HANDLE g_Disk, g_Orange, g_Apple; int main()
{
g_Disk = CreateSemaphore(NULL, 1, 1, NULL); //初始化盘子信号量,设置盘子为空
g_Orange = CreateSemaphore(NULL, 0, 1, NULL);
g_Apple = CreateSemaphore(NULL, 0, 1, NULL); //启动三个线程
const int THREAD_NUM = 3;
HANDLE handle[THREAD_NUM];
handle[0] = CreateThread(NULL, 0, FatherThread, NULL, 0, NULL);
handle[1] = CreateThread(NULL, 0, DaughterThread, NULL, 0, NULL);
handle[2] = CreateThread(NULL, 0, SonThread, NULL, 0, NULL); getchar(); //不阻塞输入,用来结束程序
CloseHandle(g_Disk);
CloseHandle(g_Apple);
CloseHandle(g_Orange);
for (int i = 0; i < THREAD_NUM; i++)
{
CloseHandle(handle[i]);
}
return 0;
} DWORD WINAPI FatherThread(LPVOID)
{
while (1)
{
WaitForSingleObject(g_Disk, INFINITE);
Sleep(1000);
if (rand() % 2 == 0)
{
cout << "爸爸向盘子中放入了一个橘子!" << endl;
ReleaseSemaphore(g_Orange, 1, NULL);
}
else
{
cout << "爸爸向盘子中放入了一个苹果!" << endl;
ReleaseSemaphore(g_Apple, 1, NULL);
}
} return 0;
} DWORD WINAPI DaughterThread(LPVOID)
{
while (1)
{
WaitForSingleObject(g_Apple, INFINITE);
Sleep(1000);
cout << "\t\t\t女儿取走了盘子中的苹果!" << endl;
ReleaseSemaphore(g_Disk, 1, NULL);
} return 0;
} DWORD WINAPI SonThread(LPVOID)
{
while (1)
{
WaitForSingleObject(g_Orange, INFINITE);
Sleep(1000);
cout << "\t\t\t儿子取走了盘子中的橘子!" << endl;
ReleaseSemaphore(g_Disk, 1, NULL);
} return 0;
}

运行结果如下所示:

windows多线程(九) PV原语分析同步问题的更多相关文章

  1. 总结windows多线程同步互斥

    windows多线程同步互斥--总结 我的windows多线程系列文章: windows多线程--原子操作 windows多线程同步--事件 windows多线程同步--互斥量 windows多线程同 ...

  2. windows多线程同步互斥--总结

    我的windows多线程系列文章: windows多线程--原子操作 windows多线程同步--事件 windows多线程同步--互斥量 windows多线程同步--临界区 windows多线程同步 ...

  3. windows多线程同步--临界区

    推荐参考博客:秒杀多线程第五篇 经典线程同步 关键段CS   关于临界区的观念,一般操作系统书上面都有. 适用范围:它只能同步一个进程中的线程,不能跨进程同步.一般用它来做单个进程内的代码快同步,效率 ...

  4. windows多线程编程星球(一)

    以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...

  5. 信号量及PV原语

    操作系统中进程互斥和同步的实现的一个最基本的方方是使用信号量和PV原语. 信号量S的物理意义:当S≥0的时候表示,某个资源可以使用的数量,当S<0的时候,其绝对值表示等待某个资源的进程数. 一般 ...

  6. PV原语操作详解

    from http://www.blogjava.net/wxqxs/archive/2009/05/10/277320.html PV原语通过操作信号量来处理进程间的同步与互斥的问题.其核心就是一段 ...

  7. linux和windows多线程的异同

    linux多线程及线程同步和windows的多线程之间的异同 并不是所有的程序都必须采用多线程,有时候采用多线程性能还不如单线程.采用多线程的好处如下: (1)多线程之间采用相同的地址空间,共享大部分 ...

  8. Windows多线程多任务设计初步(转)

    Windows多线程多任务设计初步 [前言:]当前流行的Windows操作系统,它能同时运行几个程序(独立运行的程序又称之为进程),对于同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程 ...

  9. windows多线程没那么难

    windows多线程没那么难 作者:vpoet mail:vpoet_sir@163.com 上一博文中我们引入了CreateThread()多线程编程一个简单的例子,事实上我说windows 多线程 ...

随机推荐

  1. 【mysql】排序方操作50题练习及其答案

    1.创建数据库.相关表,并插入数据create database homework;use homework; create table class_grade(gid int primary key ...

  2. springboot之assembly的文件配置

    一.在使用springboot框架的时候,存在一个问题.就是我们配置yaml文件,需要单独提出来做参数修改.当然这个是可以通过spring.profiles.active的方式来配置dev,prod等 ...

  3. cjoj P1435 - 【模板题 USACO】AC自动机 && 洛谷 P3796 【模板】AC自动机(加强版)

    又打了一遍AC自动稽. 海星. 好像是第一次打trie图,很久以前就听闻这个思想了.OrzYYB~ // It is made by XZZ #include<cstdio> #inclu ...

  4. org.springframework.mail.MailSendException: Failed messages: javax.mail.SendFailedException: Invalid Addresses

    一.问题分析 org.springframework.mail.MailSendException: Failed messages: javax.mail.SendFailedException: ...

  5. 模拟UNIX(linux)文件系统

    操作系统课程设计 一.实验内容 1. 题目:模拟UNIX(linux)文件系统                [问题描述] 在任一OS下,建立一个大文件,把它假象成一张盘,在其中实现一个简单的 模拟U ...

  6. TensorFlow API 汉化

    TensorFlow API 汉化 模块:tf   定义于tensorflow/__init__.py. 将所有公共TensorFlow接口引入此模块. 模块 app module:通用入口点脚本. ...

  7. 关于恶意说说自动在QQ空间转发的机制

    有些很讨厌的带链接说说,只要你在手机打开它,就会自动转发,内容极其不雅 一怒之下我决定看个究竟首先,在此页开头有此关键语句: <iframe src="http://rtb.map.q ...

  8. linux设置禁止ping

    linux禁止ping为了服务器的安全, 防止网络攻击(DOS 攻击消耗网络宽带,CPU资源), 需要服务器设置 禁止ping通常有两种方式第一种是通过防火墙 iptables 设置第二种是内核设置 ...

  9. Python练习——矩形、直角三角形、乘法表

    一.矩形 #******输入行和列,打印相应的矩形******# width = input("宽:") longth = input("长:") if (wi ...

  10. 二级域名 cookie session 共享

    setcookie('login','12345',0,'/','.abc.com'); session_set_cookie_params(0,'/','.abc.com');session_sta ...