信號量與臨界資源的使用——雙向道路汽車過窄橋

         臨界資源或臨界區是指在同一時刻只允許一個進程或線程訪問,並且只有當佔有該資源的進程釋放了該資源後,才能被其他進程使用。因此需要設計一種機制保障進程間的通信,使得不同的進程能夠知道臨界資源的使用情況,當某個進程佔據了臨界資源時,應該告知其他進程該資源已經被佔用,避免其他進程錯誤的訪問和使用臨界資源。信號量即是一種進程間通信的方法,它使用一個整形變量來累計喚醒次數,供以後使用,當信號量只有兩種狀態時,表示該資源只能被喚醒一次或者佔用一次,此時對臨界資源的訪問就是互斥的。

       在這裏我設計了一個多線程編程的小程序,通過動畫的形式展示出來上述調度過程。設計了一個雙向單車道的道路上中間有一個窄橋,一次只允許一輛車通過。因此不同方向的來車在通過窄橋時候應該首先判斷橋是否爲空,只有爲空的情況下才能通過,並且當佔有橋時候,還要告訴其他車輛該橋已經有車通過。因此在程序中設置了一個表示臨界資源——橋的信號量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;
}

程序運行結果;






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章