信号量与临界资源的使用——双向道路汽车过窄桥
来源:互联网 发布:金仕达交易软件 官网 编辑:程序博客网 时间:2024/04/29 00:16
临界资源或临界区是指在同一时刻只允许一个进程或线程访问,并且只有当占有该资源的进程释放了该资源后,才能被其他进程使用。因此需要设计一种机制保障进程间的通信,使得不同的进程能够知道临界资源的使用情况,当某个进程占据了临界资源时,应该告知其他进程该资源已经被占用,避免其他进程错误的访问和使用临界资源。信号量即是一种进程间通信的方法,它使用一个整形变量来累计唤醒次数,供以后使用,当信号量只有两种状态时,表示该资源只能被唤醒一次或者占用一次,此时对临界资源的访问就是互斥的。
在这里我设计了一个多线程编程的小程序,通过动画的形式展示出来上述调度过程。设计了一个双向单车道的道路上中间有一个窄桥,一次只允许一辆车通过。因此不同方向的来车在通过窄桥时候应该首先判断桥是否为空,只有为空的情况下才能通过,并且当占有桥时候,还要告诉其他车辆该桥已经有车通过。因此在程序中设置了一个表示临界资源——桥的信号量bridgeMutex,初始化为0,当有车占有桥时候,即将信号量设置为1,其他要上桥的车辆即被阻塞,当车辆通过桥后,就唤醒信号量bridgeMutex,重新设置为0.此时其他车辆就可以访问桥了。在这个程序中每一个车辆是一个线程。测试的时候生成了两个车辆,也就是两个线程,当两个车辆行驶到桥的时候,会发现其中一个车辆会等另外一个车辆先通过后,自己再通过。先通过的车辆即抢先占据临界资源的车辆。
程序是采用C语言编程的,建立的是.cpp文件,需要配置多线程编程的环境,采用的是POSIX线程标准的Pthread. 另外为了通过动画演示,配置了一个easyx图形库的环境。
C程序源代码如下:
#include <pthread.h>
#include <iostream>
#include "easyx.h"
#include <graphics.h>
#include "time.h"
#pragma comment(lib, "pthreadVC2.lib")
int bridgeMutex=0;
int rightEnd=617,leftEnd=1;
int moveStep=22,goRight=295,goLeft=320,onBridge=307;
int leftRodeUp[12],leftRodeDown[12],rightRodeUp[12],rightRodeDown[12],bridge[5];
void* carGoRight(void* args);
void* carGoLeft(void* args);
int drawGoRight(int i,int j);
int drawGoLeft(int i,int j);
int drawRode();
int main(){
pthread_t goRight[10];
pthread_t goLeft[10];
int i=0;
initgraph(640,640);
for (i=0;i<12;i++)
{
leftRodeUp[i]=0;
leftRodeDown[i]=0;
rightRodeUp[i]=0;
rightRodeDown[i]=0;
if(i<5)
{
bridge[i]=0;
}
}
drawRode();
for(i=0;i<1;i++)
{
pthread_create(&goRight[i],NULL,carGoRight,NULL);
pthread_create(&goLeft[i],NULL,carGoLeft,NULL);
pthread_join(goRight[i],NULL);
pthread_join(goLeft[i],NULL);
}
Sleep(2000);
return 0;
}
void* carGoRight(void* args)
{
int i=1,j=295,k=0;
while(i<=rightEnd)
{
k=(i-1)/moveStep;
if (k<12)
{
while (leftRodeUp[k]==1)
{
Sleep(100);
}
leftRodeUp[k]=1;
if (k>0)
{
leftRodeUp[k-1]=0;
clearrectangle(i-22,j+4,i,j+5+19); //清除原来位置的车
}
drawGoRight(i+1,j+5);
i += 22;
}
else if (k==12) //等待上桥
{
while (bridgeMutex==1)
{
Sleep(100);
}
bridgeMutex=1; //占有临界区——窄桥
bridge[k-12]=1;
leftRodeUp[k-1]=0;
clearrectangle(i-22,j+4,i,j+5+19);
drawGoRight(i+1,j+5+12);
i += 22;
}
else if(k<17)
{
bridge[k-12]=1;
bridge[k-12-1]=0;
clearrectangle(i-22,j+4+12,i,j+5+19+12);
drawGoRight(i+1,j+5+12);
i += 22;
}
else if (k==17) //进入右边道路,释放桥
{
while (rightRodeUp[k-17]==1)
{
Sleep(100);
}
rightRodeUp[k-17]=1;
bridge[k-12-1]=0;
bridgeMutex=0;
clearrectangle(i-22,j+4+12,i,j+5+19+12);
drawGoRight(i+1,j+5);
i += 22;
}
else if (k<29)//在右边道路上
{
while (rightRodeUp[k-17]==1)
{
Sleep(100);
}
rightRodeUp[k-17]=1;
rightRodeUp[k-17-1]=0;
clearrectangle(i-22,j+4,i,j+5+19);
drawGoRight(i+1,j+5);
i += 22;
}
Sleep(300);
}
rightRodeUp[11]=0;
clearrectangle(i-22,j+4,i,j+5+19);
return NULL;
}
void* carGoLeft(void* args)
{
int i=rightEnd,j=320,k=0;
while(i>=leftEnd)
{
k=(rightEnd-i)/moveStep;
if (k<12) //在左边道路上
{
while (rightRodeDown[11-k]==1)
{
Sleep(100);
}
rightRodeDown[11-k]=1;
if (k>0)
{
rightRodeDown[11-k+1]=0;
clearrectangle(i+22,j+4,i+44,j+5+19); //清除原来位置的车
}
drawGoLeft(i+1,j+5);
i -= 22;
}
else if (k==12) //等待上桥
{
while (bridgeMutex==1)
{
Sleep(100);
}
bridgeMutex=1; //占有临界区——窄桥
bridge[16-k]=1;
rightRodeDown[11-k+1]=0;
clearrectangle(i+22,j+4,i+44,j+5+19);
drawGoLeft(i+1,j+5+12-25);
i -= 22;
}
else if(k<17)
{
bridge[16-k]=1;
bridge[16-k+1]=0;
clearrectangle(i+22,j+4+12-25,i+44,j+5+19+12-25);
drawGoLeft(i+1,j+5+12-25);
i -= 22;
}
else if (k==17) //进入左边道路,释放桥
{
while (leftRodeDown[28-k]==1)
{
Sleep(100);
}
leftRodeDown[28-k]=1;
bridge[17-k]=0;
bridgeMutex=0;
clearrectangle(i+22,j+4+12-25,i+44,j+5+19+12-25);
drawGoLeft(i+1,j+5);
i -= 22;
}
else if (k<29)//在左边道路上
{
while (leftRodeDown[28-k]==1)
{
Sleep(100);
}
leftRodeDown[28-k]=1;
leftRodeDown[28-k+1]=0;
clearrectangle(i+22,j+4,i+44,j+5+19);
drawGoLeft(i+1,j+5);
i -= 22;
}
Sleep(300);
}
leftRodeDown[0]=0;
clearrectangle(1,j+4,1+22,j+5+19);
return NULL;
}
int drawGoRight(int i,int j)
{
rectangle(i,j,i+20,j+15);
solidcircle(i+5,j+15,3);
solidcircle(i+15,j+15,3);
line(i+7,j+5,i+13,j+5);
line(i+13,j+5,i+11,j+3);
line(i+13,j+5,i+11,j+8);
return 1;
}
int drawGoLeft(int i,int j)
{
rectangle(i,j,i+20,j+15);
solidcircle(i+5,j+15,3);
solidcircle(i+15,j+15,3);
line(i+7,j+5,i+13,j+5);
line(i+7,j+5,i+9,j+3);
line(i+7,j+5,i+9,j+8);
return 1;
}
int drawRode()
{
//clearrectangle(i-1,j-1,i+21,j+19);
line(0,295,265,295);//left rode
line(0,345,265,345);
line(0,320,265,320);
line(265,307,265,295);
line(265,333,265,345);
line(265,307,375,307);//bridge
line(265,333,375,333);
line(375,295,640,295);//right rode
line(375,345,640,345);
line(375,320,640,320);
line(375,295,375,307);
line(375,345,375,333);
return 1;
}
程序运行结果;
- 信号量与临界资源的使用——双向道路汽车过窄桥
- Win32 线程的创建&信号量临界资源&事件对象
- 互斥量、临界区、信号量和时间的作用与区别
- 互斥量、临界区、信号量和时间的作用与区别
- 互斥量、临界区、信号量和时间的作用与区别
- WaitForSingleObject与事件、信号量、互斥、临界区的用法
- WaitForSingleObject与事件、信号量、互斥、临界区的用法
- 临界资源、临界区、信号量、P,V操作
- 17.进程同步与死锁——信号量临界区保护
- 线程同步——临界区,互斥量,信号量,事件
- [MFC]同步对象——CCriticalSection临界区,CSemaphore信号量
- 互斥量、临界区、信号量——来来来,看你晕不晕
- 多线程【临界区-临界资源的理解】
- 关于等待队列和信号量的好文章 (信号量是为了进入临界区的资源独占,而等待队列可能是为了当前资源不可用)
- 临界区,互斥量,信号量,事件的区别
- 临界区,互斥量,信号量,事件的区别
- 临界区,互斥量,信号量,事件的区别
- 临界区,互斥量,信号量,事件的区别
- c#使用正则表达式获取json中的数组
- tomcat启动时Several ports (8080, 8009) required by Tomcat v6.0 Server at localhost are already in use.
- 危险的“我以为”DDoS&丑陋的现实
- Java 集合系列之 HashMap详细介绍(源码解析)和使用示例
- 使用jquery在前台页面验证邮箱输入是否正确
- 信号量与临界资源的使用——双向道路汽车过窄桥
- git push提交分支错误记录
- [React Native]豆瓣电影APP Demo
- 命名参数是c#4.0新增的一个方法调用功能
- Markdown编辑器使用使用说明--菜鸟自留
- JavaScript学习笔记(一)
- 4561: [JLoi2016]圆的异或并
- 如何学习正则表达式?总结一个分类
- Android 长连接实现