【发布时间】:2022-01-01 01:41:39
【问题描述】:
我正在尝试解决信号量代表道路的练习的线程同步问题。这条路一次最多可支持 3 辆同向行驶的汽车,应避免挨饿。到目前为止,我下面的代码似乎通过在道路空旷时改变活动方向来避免饥饿。但是,在 numOfCarsOnRoad 更新为非零之前,似乎有超过 3 个汽车/线程可以到达 sem_wait() 行。这意味着(正如您在输出中看到的那样),有时,道路上挤满了 3 辆车,一旦它们开始离开,那些设法到达 sem_wait 的额外车辆,继续进入,当它们完成时,然后是方向更改生效。我很难理解如何防止超过 3 个汽车/线程到达 sem_wait 行,而是等待。
我试图实现的逻辑是最多三辆汽车可以进入信号量(并不总是 3,取决于在状态变量更新之前到达该点的数量),然后任何向另一个方向行驶的汽车都需要等到活动方向改变并且有更多车辆朝同一方向行驶,则需要等到它们的方向在另一轮中再次变为活动状态。
谁能指出我正确的方向或指出我的逻辑有缺陷的地方吗?
nr.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <stdbool.h>
#include "nr.h"
sem_t sem;
pthread_mutex_t mutex;
unsigned int numOfCarsOnRoad = 0;
unsigned int carsGoingW = 0;
unsigned int carsGoingE = 0;
unsigned long numOfCars = 0; // used for thread initializations
char currActiveDir; // either W or E
bool currDirInitialized = false;
void *crossBridge(void *i)
{
int id = *((int *)i);
char direction[5];
if (rand() % 2 == 0)
{
strcpy(direction, "West");
carsGoingW++;
}
else
{
strcpy(direction, "East");
carsGoingE++;
}
if (!currDirInitialized)
{
currActiveDir = direction[0];
currDirInitialized = true;
}
while (currActiveDir != direction[0] || numOfCarsOnRoad != 0)
sleep(2);
sem_wait(&sem); // enter critical region
printf("Car #%d waiting to pass to the %s...\n", id, direction);
pthread_mutex_lock(&mutex);
numOfCarsOnRoad++;
printf("Car #%d going to the %s. Number of cars on the road = %d\n", id, direction, numOfCarsOnRoad);
pthread_mutex_unlock(&mutex);
sleep(1); // cross the road
if (direction[0] == 'W')
carsGoingW--;
else
carsGoingE--;
pthread_mutex_lock(&mutex);
numOfCarsOnRoad--;
printf("Car #%d crossed to the %s! Number of cars on the road = %d\n", id, direction, numOfCarsOnRoad);
if (numOfCarsOnRoad == 0) // avoid starvation
{
if (currActiveDir == 'W' && carsGoingE > 0)
currActiveDir = 'E';
else if (currActiveDir == 'E' && carsGoingW > 0)
currActiveDir = 'W';
}
pthread_mutex_unlock(&mutex);
sem_post(&sem);
free(i);
pthread_exit(NULL);
}
void parseCarArg(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++)
{
if (strcmp(argv[i], "-c") == 0)
{
if (++i < argc && strlen(argv[i]) > 0)
numOfCars = strtol(argv[i], NULL, 10); // convert to long
if (numOfCars == 0)
{
perror("You must enter a number of cars > 0!\n");
exit(EXIT_FAILURE);
}
break;
}
}
}
int main(int argc, char *argv[])
{
if (argc == 0)
exit(EXIT_FAILURE);
parseCarArg(argc, argv);
srand(time(NULL)); // seed the generator using epoch time in millis
if (sem_init(&sem, 0, 3) == -1)
{
perror("Failed to initialize semaphore!\n");
exit(EXIT_FAILURE);
}
if (pthread_mutex_init(&mutex, NULL) != 0)
{
perror("Failed to initialize mutex!\n");
exit(EXIT_FAILURE);
}
pthread_t cars[numOfCars];
int i;
for (i = 0; i < numOfCars; i++)
{
int *id = malloc(sizeof(int));
*id = i;
if (pthread_create(&cars[i], NULL, crossBridge, id) != 0)
{
perror("Failed to create threads for the cars!\n");
exit(EXIT_FAILURE);
}
}
// wait for all threads to finish
for (i = 0; i < numOfCars; i++)
pthread_join(cars[i], NULL);
sem_destroy(&sem);
pthread_mutex_destroy(&mutex);
return 0;
}
nr.h:
void * crossBridge(void *i);
void parseCarArg(int argc, char *argv[]);
以及以 -c 20 作为输入的示例输出:
Car #0 waiting to pass to the West...
Car #0 going to the West. Number of cars on the road = 1
Car #1 waiting to pass to the West...
Car #1 going to the West. Number of cars on the road = 2
Car #1 crossed to the West! Number of cars on the road = 1
Car #0 crossed to the West! Number of cars on the road = 0
Car #2 waiting to pass to the East...
Car #2 going to the East. Number of cars on the road = 1
Car #2 crossed to the East! Number of cars on the road = 0
Car #18 waiting to pass to the West...
Car #18 going to the West. Number of cars on the road = 1
Car #17 waiting to pass to the West...
Car #17 going to the West. Number of cars on the road = 2
Car #4 waiting to pass to the West...
Car #4 going to the West. Number of cars on the road = 3
Car #4 crossed to the West! Number of cars on the road = 2
Car #9 waiting to pass to the West...
Car #17 crossed to the West! Number of cars on the road = 1
Car #5 waiting to pass to the West...
Car #18 crossed to the West! Number of cars on the road = 0
Car #9 going to the West. Number of cars on the road = 1
Car #5 going to the West. Number of cars on the road = 2
Car #16 waiting to pass to the East...
Car #16 going to the East. Number of cars on the road = 3 <-- example of where the issue occurs
Car #9 crossed to the West! Number of cars on the road = 2
Car #5 crossed to the West! Number of cars on the road = 1
Car #11 waiting to pass to the East...
Car #11 going to the East. Number of cars on the road = 2
Car #8 waiting to pass to the East...
Car #8 going to the East. Number of cars on the road = 3
Car #16 crossed to the East! Number of cars on the road = 2
Car #19 waiting to pass to the East...
Car #19 going to the East. Number of cars on the road = 3
Car #11 crossed to the East! Number of cars on the road = 2
Car #8 crossed to the East! Number of cars on the road = 1
Car #3 waiting to pass to the East...
Car #3 going to the East. Number of cars on the road = 2
Car #6 waiting to pass to the East...
Car #6 going to the East. Number of cars on the road = 3
Car #19 crossed to the East! Number of cars on the road = 2
Car #12 waiting to pass to the East...
Car #12 going to the East. Number of cars on the road = 3
Car #6 crossed to the East! Number of cars on the road = 2
Car #3 crossed to the East! Number of cars on the road = 1
Car #7 waiting to pass to the East...
Car #7 going to the East. Number of cars on the road = 2
Car #12 crossed to the East! Number of cars on the road = 1
Car #7 crossed to the East! Number of cars on the road = 0
Car #15 waiting to pass to the West...
Car #13 waiting to pass to the West...
Car #15 going to the West. Number of cars on the road = 1
Car #14 waiting to pass to the West...
Car #14 going to the West. Number of cars on the road = 2
Car #13 going to the West. Number of cars on the road = 3
Car #13 crossed to the West! Number of cars on the road = 2
Car #14 crossed to the West! Number of cars on the road = 1
Car #15 crossed to the West! Number of cars on the road = 0
Car #10 waiting to pass to the West...
Car #10 going to the West. Number of cars on the road = 1
Car #10 crossed to the West! Number of cars on the road = 0
【问题讨论】:
-
您的问题标题抓住了解决方案:如果您必须使用信号量来表示网桥的容量,那么在到达信号量之前您需要另一个同步点。我知道您在必须使用的工具中先验受到限制,但是John Bollinger is quite right:计数信号量非常不适合这个问题。我怀疑我们要么遗漏了一些关于允许的解决方案,要么你的老师对如何解决这个问题有一个错误的想法。
-
@pilcrow 感谢您的评论。我只是很难理解如何在信号量之前和两个 while 循环之后同步线程。我再试一次。至于允许的解决方案和方法,遗憾的是我没有遗漏任何内容。这些是他们为此练习设置的约束。他们提到这是为了让我们了解它们的工作原理,但我想正确使用它们并不是他们的首要任务。只是他们希望我们遗憾地看到的功能
标签: c multithreading pthreads semaphore