首页 > 解决方案 > 在多线程程序中使用时计数器值不一致

问题描述

我正在用 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;
}

标签: cpthreads

解决方案


推荐阅读