实习作业:多线程基础编程实践
pass_bridge.cpp
/*
* compile: g++ -o pass_bridge.out pass_bridge.cpp -lpthread
* run: ./pass_bridge.out
* this programe should run on a linux OS
*
*
*
*/
//head files
#include <sys/socket.h>
#include <sys/types.h>
#include <poll.h>
#include <unistd.h>
#include <netdb.h>
#include <error.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <list>
#include <iterator>
#include <algorithm>
#include "randutil.h"
#include "car.h"
//init param
pthread_mutex_t mutex1; //use when changing count1
pthread_mutex_t mutex2; //use when changing count2
pthread_mutex_t output; //use when the programe needs output
int count1 = 0; //the number of cars waiting on the leftside to pass through the bridge
int count2 = 0; // cars waiting on the right side ...
/*
* -1 stands for no cars requests for passing
* Car::LEFT_TO_RIGHT means cars waiting on the left side got the chance to passing through
* Car::RIGHT_TO_LEFT means cars waiting on the right side got the chance to passing through
*/
int state=-1;
std::list<Car *> cars;
//configure info
int pass_sleep_time_width = 3;
int car_join_sleep_time_width = 3;
#define NUM_CARS 20 //number of cars
int car_seq_width = 3;
Car arr_cars[NUM_CARS];
//comparator
bool CompareRules(Car* x, Car* y)
{
if(x->sq < y->sq)
return true;
else
return false;
}
//show the state of the bridge
void show_state()
{
//printf("state = %d\n",state);
cars.sort(CompareRules);
std::list<Car *>::iterator it=cars.begin();
for(;it!=cars.end();it++)
{
if((*it)->state == Car::WAIT && (*it)->dir == Car::LEFT_TO_RIGHT)
printf("[%d] ",(*it)->id);
}
if(state == Car::LEFT_TO_RIGHT)
printf(" -> ");
else if(state == Car::RIGHT_TO_LEFT)
printf(" <- ");
if(state == -1)
printf(" -- ---- --");
else
{
it=cars.begin();
for(;it!=cars.end();it++)
{
if((*it)->state == Car::PASSING)
printf("[%d] ",(*it)->id);
}
}
if(state == Car::LEFT_TO_RIGHT)
printf(" -> ");
else if(state == Car::RIGHT_TO_LEFT)
printf(" <- ");
it=cars.begin();
for(;it!=cars.end();it++)
{
if((*it)->state == Car::WAIT && (*it)->dir == Car::RIGHT_TO_LEFT)
printf("[%d] ",(*it)->id);
}
puts("");
}
void *left_to_right(void * arg)
{
Car * c = &arr_cars[*((int *)arg)];
pthread_mutex_lock(&output);
c->pass();
c->state=Car::WAIT;
pthread_mutex_unlock(&output);
pthread_mutex_lock(&output);
show_state();
pthread_mutex_unlock(&output);
//P(S1)
pthread_mutex_lock(&mutex1);
//IF(COUNT1==0)
if(count1==0){
//P(S2)
pthread_mutex_lock(&mutex2);
state = Car::LEFT_TO_RIGHT;
}
//COUNT1++
count1++;
//V(S1)
pthread_mutex_unlock(&mutex1);
//PASSING THROUGH
pthread_mutex_lock(&output);
c->passing();
c->state=Car::PASSING;
pthread_mutex_unlock(&output);
pthread_mutex_lock(&output);
show_state();
pthread_mutex_unlock(&output);
usleep(RANDOM::getNumber(pass_sleep_time_width));
//P(S1)
pthread_mutex_lock(&mutex1);
//COUNT1--
count1--;
//IF(COUNT1==0)
if(count1==0){
//V(S2)
pthread_mutex_unlock(&mutex2);
state = -1;
}
//V(S1)
pthread_mutex_unlock(&mutex1);
pthread_mutex_lock(&output);
c->passed();
c->state=Car::PASSED;
pthread_mutex_unlock(&output);
pthread_mutex_lock(&output);
show_state();
pthread_mutex_unlock(&output);
pthread_exit(0);
}
void *right_to_left(void * arg)
{
Car * c = &arr_cars[*((int *)arg)];
pthread_mutex_lock(&output);
c->pass();
c->state=Car::WAIT;
pthread_mutex_unlock(&output);
pthread_mutex_lock(&output);
show_state();
pthread_mutex_unlock(&output);
//P(S2)
pthread_mutex_lock(&mutex2);
//IF(COUNT2==0)
if(count2==0){
//P(S1)
pthread_mutex_lock(&mutex1);
state = Car::RIGHT_TO_LEFT;
}
//COUNT2++
count2++;
//V(S2)
pthread_mutex_unlock(&mutex2);
//PASSING THROUGH
pthread_mutex_lock(&output);
c->passing();
c->state=Car::PASSING;
pthread_mutex_unlock(&output);
pthread_mutex_lock(&output);
show_state();
pthread_mutex_unlock(&output);
usleep(RANDOM::getNumber(pass_sleep_time_width));
//P(S2)
pthread_mutex_lock(&mutex2);
//COUNT2--
count2--;
//IF(COUNT2==0)
if(count2==0){
//V(S1)
pthread_mutex_unlock(&mutex1);
state = -1;
}
//V(S2)
pthread_mutex_unlock(&mutex2);
pthread_mutex_lock(&output);
c->passed();
c->state=Car::PASSED;
pthread_mutex_unlock(&output);
pthread_mutex_unlock(&output);
show_state();
pthread_mutex_unlock(&output);
pthread_exit(0);
}
int main()
{
pthread_t tid1,tid2;
int num=0;
for(int i=0;i<NUM_CARS;i++)
{
arr_cars[i].id = RANDOM::getNumber(car_seq_width);
arr_cars[i].sq = ++num;
cars.push_back(&arr_cars[i]);
}
std::list<Car *>::iterator it=cars.begin();
int num_cars = NUM_CARS;
num = 0;
while(num_cars--){
int who = RANDOM::getNumber(2);
if(who%2==0){
(*it)->dir = Car::LEFT_TO_RIGHT;
pthread_create(&tid1,NULL,left_to_right,&num);
}
else
{
(*it)->dir = Car::RIGHT_TO_LEFT;
pthread_create(&tid2,NULL,right_to_left,&num);
}
usleep(RANDOM::getNumber(car_join_sleep_time_width));
num++;
it++;
}
return 0;
}
car.h
#include <stdio.h>
class Car{
public:
static const int LEFT_TO_RIGHT = 0;
static const int RIGHT_TO_LEFT = 1;
static const int OUT = 0;
static const int WAIT = 1;
static const int PASSING = 2;
static const int PASSED = 3;
int dir;
int id;
int sq;
int state;
Car(){}
Car(int id,int dir,int num)
{
sq = num;
this->id=id;
this->dir=dir;
state = Car::OUT;
}
Car(int id,int num)
{
sq = num;
this->id=id;
state = Car::OUT;
}
void pass()
{
if(dir==Car::LEFT_TO_RIGHT)
{
printf(">-- :car %d requests for passing\n",this->id);
}
else
{
printf("--< :car %d requests for passing\n",this->id);
}
}
void passing()
{
if(dir==Car::LEFT_TO_RIGHT)
{
printf("->- :car %d is passing\n",this->id);
}
else
{
printf("-<- :car %d is passing\n",this->id);
}
}
void passed()
{
if(dir==Car::LEFT_TO_RIGHT)
{
printf("--> :car %d has passed\n",this->id);
}
else
{
printf("<-- :car %d has passed\n",this->id);
}
}
};
randutil.h
#include <stdlib.h>
#include <time.h>
class RANDOM
{
public:
//width stands for its width
static long getNumber(int width)
{
width--;
long ret=0;
ret = rand()%9+1;
long range=1;
while(width--)
{
ret*=10;
range*=10;
}
return ret+rand()%range;
}
};
运行结果:
[root@bogon mutex]# g++ -o pass_bridge.out pass_bridge.cpp -lpthread
[root@bogon mutex]# ./pass_bridge.out
--< :car 286 requests for passing
-- ---- --[286]
-<- :car 286 is passing
<- [286] <-
<-- :car 286 has passed
-- ---- --
>-- :car 115 requests for passing
[115] -- ---- --
->- :car 115 is passing
-> [115] ->
--> :car 115 has passed
-- ---- --
>-- :car 635 requests for passing
[635] -- ---- --
->- :car 635 is passing
-> [635] ->
--> :car 635 has passed
-- ---- --
--< :car 292 requests for passing
-- ---- --[292]
-<- :car 292 is passing
<- [292] <-
<-- :car 292 has passed
-- ---- --
--< :car 721 requests for passing
-- ---- --[721]
-<- :car 721 is passing
<- [721] <-
<-- :car 721 has passed
-- ---- --
--< :car 627 requests for passing
-- ---- --[627]
-<- :car 627 is passing
<- [627] <-
<-- :car 627 has passed
-- ---- --
>-- :car 659 requests for passing
[659] -- ---- --
->- :car 659 is passing
-> [659] ->
>-- :car 626 requests for passing
[626] -> [659] ->
->- :car 626 is passing
-> [659] [626] ->
--> :car 659 has passed
-> [626] ->
--> :car 626 has passed
-- ---- --
--< :car 726 requests for passing
-- ---- --[726]
-<- :car 726 is passing
<- [726] <-
<-- :car 726 has passed
-- ---- --
>-- :car 836 requests for passing
[836] -- ---- --
->- :car 836 is passing
-> [836] ->
--> :car 836 has passed
-- ---- --
>-- :car 968 requests for passing
[968] -- ---- --
->- :car 968 is passing
-> [968] ->
>-- :car 729 requests for passing
[729] -> [968] ->
->- :car 729 is passing
-> [968] [729] ->
--> :car 968 has passed
-> [729] ->
>-- :car 930 requests for passing
[930] -- ---- --
->- :car 930 is passing
-> [729] [930] ->
--> :car 729 has passed
-> [930] ->
--> :car 930 has passed
-- ---- --
--< :car 923 requests for passing
-- ---- --[923]
-<- :car 923 is passing
<- [923] <-
<-- :car 923 has passed
-- ---- --
--< :car 235 requests for passing
-- ---- --[235]
-<- :car 235 is passing
<- [235] <-
>-- :car 602 requests for passing
[602] <- [235] <-
<-- :car 235 has passed
[602] -- ---- --
->- :car 602 is passing
-> [602] ->
--> :car 602 has passed
-- ---- --
--< :car 158 requests for passing
-- ---- --[158]
-<- :car 158 is passing
<- [158] <-
<-- :car 158 has passed
-- ---- --
--< :car 667 requests for passing
-- ---- --[667]
-<- :car 667 is passing
<- [667] <-
<-- :car 667 has passed
-- ---- --
--< :car 256 requests for passing
-- ---- --[256]
-<- :car 256 is passing
<- [256] <-
--< :car 542 requests for passing
-- ---- --[542]
-<- :car 542 is passing
<- [256] [542] <-
<-- :car 256 has passed
<- [542] <-