c - 在多线程程序中使用时计数器值不一致
问题描述
我正在用 C 语言做一个任务,我们有一条狭窄的道路,一次最多只能支持三辆汽车。这条路是单向的,所以汽车可以向东或向西行驶。饥饿也应该避免。到目前为止,我的实现似乎可以正常工作,但我很难理解为什么该numOfCarsOnRoad
变量的值不一致(即在输出中两次打印“路上的汽车数量 = 1”而不是“.. = 3”、“ .. = 2', '.. = 1') 尽管每个线程每次都增加/减少它。
此外,我注意到,例如,如果三个线程一个接一个地“启动”(因此调用 sleep(1)),它们可能以不同的顺序完成。我知道每个线程都在一个单独的轻量级进程中运行,但是对于先运行的线程来说,睡眠(1)不应该持续更短吗?有没有办法避免这种情况?
汽车的数量(由线程表示)通过 cmd args 传递(即'-c 5')。
标题:
void * crossBridge(void *i);
void parseCarArg(int argc, char *argv[]);
C:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include "ask2.h"
sem_t sem;
int numOfCarsOnRoad = 0;
int carsGoingW = 0;
int carsGoingE = 0;
long numOfCars = 0; // used for thread initializations
char currActiveDir = '_'; // either W or E ( _ initially)
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 (currActiveDir == '_')
currActiveDir = direction[0];
printf("Car #%d waiting to pass to the %s...\n", id, direction);
while (currActiveDir != direction[0] || numOfCarsOnRoad == 3)
{
sleep(2);
}
sem_wait(&sem); // enter critical region
numOfCarsOnRoad++;
printf("Car #%d going to the %s. Number of cars on the road = %d\n", id, direction, numOfCarsOnRoad);
sleep(1);
numOfCarsOnRoad--;
sem_post(&sem);
printf("Car #%d crossed to the %s! Number of cars on the road = %d\n", id, direction, numOfCarsOnRoad);
if(direction[0] == 'W') carsGoingW--;
else carsGoingE--;
// helps to avoid starvation
if (numOfCarsOnRoad == 0)
{
if (currActiveDir == 'W' && carsGoingE > 0)
currActiveDir = 'E';
else if (currActiveDir == 'E' && carsGoingW > 0)
currActiveDir = 'W';
}
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);
}
pthread_t cars[numOfCars];
int i;
for (i = 0; i < numOfCars; i++)
{
if (pthread_create(&cars[i], NULL, crossBridge, &i) != 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);
return 0;
}
解决方案
推荐阅读
- ios - 错误:仍在上传屏幕截图。关于 Apple App 提交
- sql - 计算相似子字符串 SQL 查询
- r - 在 R 中设置工作目录的最佳实践
- amazon-web-services - AWS Private API Gateway - 不是有效的键=值对(缺少等号)
- sql-server - SQL Server - 带有 string_agg 的索引视图
- r - 使用 read_table 读取 tidyverse 中带有引号的标题名称的文件
- google-cloud-functions - GCP 云函数何时确认发布/订阅消息?
- elasticsearch - ElasticSearch 将新的传入文档流式传输到客户端
- javascript - 7天后删除特定文件
- java - 当我使用 apache commons CLI 传递三个以上的选项时,结果显示为 NULL 第三个选项