我试图使用线程和互斥锁来模拟交集.
我有去海峡的功能,左转,右转.现在,我有一个接近十字路口的功能.这会产生随机方向并转向.每个线程共享接近的交叉点.
我为所有方向的所有汽车定义了所有锁.
采取进入海峡的功能.它有一个switch语句,可以打印当时汽车正在做什么.现在,我只是不确定锁定此功能的内容.如果汽车指向北方的方向,我将锁定东西方向,同时指向南方向北的汽车?
这是我的锁只调用一个锁定或解锁的功能
#define NUMCARS 30
#define lock_NW(CAR) lock(CAR, NW_mutex)
#define lock_NE(CAR) lock(CAR, NE_mutex)
#define lock_SW(CAR) lock(CAR, SW_mutex)
#define lock_SE(CAR) lock(CAR, SE_mutex)
#define unlock_NW(CAR) unlock(CAR, NW_mutex)
#define unlock_NE(CAR) unlock(CAR, NE_mutex)
#define unlock_SW(CAR) unlock(CAR, SW_mutex)
#define unlock_SE(CAR) unlock(CAR, SE_mutex)
Run Code Online (Sandbox Code Playgroud)
这里是主要的
int main(int argc, char **argv){
/* Initial variables*/
int index, tid;
unsigned int carids[NUMCARS];
pthread_t carthreads[NUMCARS];
/* Start up a thread for each car*/
for(index = 0; index <NUMCARS; index++){
carids[index] = index;
tid = pthread_create(&carthreads[index], NULL, approachintersection, (void*)&carids[index]);
}
/* Wait for every car thread to finish */
for(index = 0; index <NUMCARS; index++){
pthread_join(carthreads[index], NULL);
}
printf("Done\n");
return 1;
}
Run Code Online (Sandbox Code Playgroud)
这是一个即将到来的交叉路口,它将功能称为海峡
static void * approachintersection(void* arg){
unsigned int * carnumberptr;
unsigned int carnumber;
orientation_t cardir = (orientation_t)random()%4;
unsigned long turn = random()%3;
carnumberptr = (unsigned int*) arg;
carnumber = (unsigned int) *carnumberptr;
if(turn==LEFT){
turnleft(cardir, carnumber);
} else if(turn==RIGHT){
turnright(cardir, carnumber);
} else {//straight
gostraight(cardir, carnumber);
}
return (void*)carnumberptr;
}
Run Code Online (Sandbox Code Playgroud)
现在,这是我要锁定适当方向的海峡功能.
/*
cardirection - The direction the car is pointing. If it is pointing NORTH,
it is starting from the South-Eastern corner of the intersection
and "going straight" means it wants to move SOUTH to NORTH.
valid options: NORTH, SOUTH, EAST, WEST
carnumber - The car identifier
*/
static void gostraight(orientation_t cardirection, unsigned int carnumber){
switch(cardirection){
case NORTH:
printf("Car %d, Moving South-North\n", carnumber);
break;
case SOUTH:
printf("Car %d, Moving North-South\n", carnumber);
break;
case EAST:
printf("Car %d, Moving West-East\n", carnumber);
break;
case WEST:
printf("Car %d, Moving East-West\n", carnumber);
break;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,如果接近的汽车从南方指向北方,那么汽车将是SE汽车,我会用lock_SE(CAR)锁定箱子东,西打印功能?防止其他线程进入并打印?所以我会锁定解锁打印语句?
或者我会锁定整个switch语句?
**编辑:这会是这样做的吗?**
static void turnleft(orientation_t cardirection, unsigned int carnumber){
int CAR;
CAR = carnumber;
switch(cardirection){
case NORTH:
lock_SE(CAR)
printf("Car %d, Moving South-West\n", carnumber);
unlock_SE(CAR)
break;
case SOUTH:
lock_NW(CAR)
printf("Car %d, Moving North-East\n", carnumber);
unlock_NW(CAR)
break;
case EAST:
lock_SW(CAR)
printf("Car %d, Moving West-North\n", carnumber);
unlock_SW(CAR)
break;
case WEST:
lock_NE(CAR)
printf("Car %d, Moving East-South\n", carnumber);
unlock_NE(CAR)
break;
}
Run Code Online (Sandbox Code Playgroud)
}
这不是一个容易的问题。我将尝试展示两种解决方案。
第一个明显的:整个交集有一个互斥锁,在turnleft, turnright, gostraightadd的开头lock(car, intersection_mutex);,就在每个函数结束之前释放所说的互斥锁。这样一次只能让一辆车通过十字路口。这样做的好处是易于理解并且不会导致死锁。缺点是一次只能一辆车进入,但众所周知,两辆行驶非相交路径的汽车可以毫无问题地进入。这是一个示例go_straight()(其他遵循相同的方法):
static void gostraight(orientation_t cardirection, unsigned int carnumber){
pthread_mutex_lock(&intersection_mutex);
switch(cardirection){
case NORTH:
printf("Car %d, Moving South-North\n", carnumber);
break;
case SOUTH:
printf("Car %d, Moving North-South\n", carnumber);
break;
case EAST:
printf("Car %d, Moving West-East\n", carnumber);
break;
case WEST:
printf("Car %d, Moving East-West\n", carnumber);
break;
}
}
pthread_mutex_unlock(&intersection_mutex);
}
Run Code Online (Sandbox Code Playgroud)
为了一次让多于一辆车进入,我们需要一种细粒度的方法。细粒度方法的问题在于实施和获得正确性要困难得多。和go_straight都turn_left需要锁定两个互斥体(您可能会说左转需要三个..)。因此,如果您无法获取两个互斥体,则需要退缩。将其转化为驾驶规则:
you must not enter the intersection before you can exit it.
Run Code Online (Sandbox Code Playgroud)
因此,要直行,我们必须首先获取离您最近的互斥体,然后是您路径中的下一个才能退出。如果我们不能同时获得两者,我们必须释放我们锁定的那一个。如果我们不释放它,我们就会陷入僵局。
为此,我将添加两个辅助函数:
static void lock_two(pthread_mutex_t *a, pthread_mutex_t *b) {
while(1) {
pthread_mutex_lock(a);
if(pthread_mutex_trylock(b) == 0)
break;
else
/* We must release the previously taken mutex so we don't dead lock the intersection */
pthread_mutex_unlock(a);
pthread_yield(); /* so we don't spin over lock/try-lock failed */
}
}
static void unlock_two(pthread_mutex_t *a, pthread_mutex_t *b) {
pthread_mutex_unlock(a);
pthread_mutex_unlock(b);
}
Run Code Online (Sandbox Code Playgroud)
这是我的直走版本:
static void gostraight(orientation_t cardirection, unsigned int carnumber){
switch(cardirection){
case NORTH:
lock_two(&SE_mutex, &NE_mutex);
printf("Car %d, Moving South-North\n", carnumber);
unlock_two(&SE_mutex, &NE_mutex);
break;
case SOUTH:
lock_two(&NW_mutex, &SW_mutex);
printf("Car %d, Moving North-South\n", carnumber);
unlock_two(&NW_mutex, &SW_mutex);
break;
case EAST:
lock_two(&SW_mutex, &SE_mutex);
printf("Car %d, Moving West-East\n", carnumber);
unlock_two(&SW_mutex, &SE_mutex);
break;
case WEST:
lock_two(&NE_mutex, &NW_mutex);
printf("Car %d, Moving East-West\n", carnumber);
unlock_two(&NE_mutex, &NW_mutex);
break;
}
}
Run Code Online (Sandbox Code Playgroud)
turn_left然后需要遵循相同的方法。
| 归档时间: |
|
| 查看次数: |
2149 次 |
| 最近记录: |