Pthreads - 具有条件变量和互斥量的生产者和消费者 - 连接错误和奇怪的 cout

Pthreads - Producer and consumer with condition variable and mutex - join error and strange cout

我正在使用 pthreads 制作多线程程序。思路很简单:

汽车和加油站都有一定的油量,汽车没油后需要去加油站。加油站没油后,加油线程运行并重新填充资源。一切似乎都很好,除了我必须使用 pthread_exit 而不是 pthread_join 来等待 main 函数中的线程,有时会出现同一辆车的双 cout"-----End of fuel-----"。 我做对了吗?

结构和一些全局变量:

#define initialFuel 100
#define loop 10

pthread_mutex_t mutex1, mutex2;
pthread_cond_t isempty;
PetrolDistributor petrolDistributor;

struct Car {
    int capacity = 10;
    int petrol = 5;
};

struct PetrolDistributor {
    int petrol = initialFuel;
    bool isEmpty = false;
};

线程:

void * threadSupply(void *arg )
{
    for(int i = 0; i<loop; i++) 
{
        pthread_mutex_lock(&mutex1);

        while(!petrolDistributor.isEmpty)
        {
            pthread_cond_wait(&isempty, &mutex1);   //When signal received, do below:
            usleep(2000000);
            petrolDistributor.petrol = initialFuel; //Refill petrol and change state
            petrolDistributor.isEmpty = false;
        }
        pthread_mutex_unlock(&mutex1);
    }
}

void * threadPetrolDriver(void *arg )
{
    Car *car;
    car = (Car*) arg;

    for(int i = 0; i<loop; i++) 
    {
        while(car->petrol > 0) // Car consumes petrol here
        {
            usleep(200000);
            cout << car->petrol << endl;
            car->petrol -= 1;
        }
        cout << "-----End of fuel-----" << "\t\t #" << i << endl;

        pthread_mutex_lock(&mutex1);
        if (petrolDistributor.petrol >= 30)  // If distributor almost empty?
        {
            petrolDistributor.petrol -= car->capacity;  //Substract car's capacity amount of fuel from distributor
            car->petrol = car->capacity;               //Fillup mentioned capacity in car
        }
        else
        {
            petrolDistributor.isEmpty = true;
            pthread_cond_signal(&isempty);
        }
        pthread_mutex_unlock(&mutex1);
    }
}

主线:

int main()
{    
    pthread_t car;
    pthread_t supply;

    Car carPetrol;

    pthread_cond_init(&isempty, NULL);
    pthread_mutex_init(&mutex1, NULL);

    pthread_create(&car, NULL, threadPetrolDriver, (void*) (&carPetrol));
    pthread_create(&supply, NULL, threadSupply, NULL);

   // pthread_join(&car, NULL);     //results error: invalid conversion from ‘pthread_t* {aka long unsigned int*}’ to ‘pthread_t {aka long unsigned int}’ [-fpermissive]|
   // pthread_join(&supply, NULL);
    pthread_exit(NULL);

    return 0;
}

输出示例:

-----End of fuel-----    #0
9
(...)
2
1
-----End of fuel-----    #1
-----End of fuel-----    #2  //Also for loop increments
10
9
(...)
3
2
1
-----End of fuel-----    #3
10
9
(...)

问题是为什么输出看起来像那样?有时五次迭代很好,第六次显示双重信息。加入有什么问题? 谢谢指教。

汽车可以显示 "End of fuel" 多次,因为如果它发现 petrolDistributor 几乎是空的,它不会等待 - 它会再次绕过 while 循环,而不会自行加油。

你在这里应该做的是让 car 在条件变量上等待,如果它发现 petrolDistributor 的燃料不足以让汽车加油。在 petrolDistributor 加油之前,它不应该继续:

pthread_mutex_lock(&mutex1);
if (petrolDistributor.petrol < 30)  // If distributor almost empty?
    pthread_cond_signal(&isempty);

// wait for sufficient fuel to be available
while (petrolDistributor.petrol < car->capacity)
    pthread_cond_wait(&carwaiting, &mutex1);

// refuel
petrolDistributor.petrol -= car->capacity;  //Substract car's capacity amount of fuel from distributor
car->petrol = car->capacity;               //Fillup mentioned capacity in car
pthread_mutex_unlock(&mutex1);

我在这里使用了一个新的条件变量 carwaiting。请注意 petrolDistributor.isEmpty 布尔值是不必要的 - 谓词只是 petrolDistributor.petrol < 30.

petrolDistributor 在为加油站加油后需要向任何等待的汽车发出信号:

    pthread_mutex_lock(&mutex1);

    // Wait for petrol to drop below low-water-mark
    while(petrolDistributor.petrol >= 30)
        pthread_cond_wait(&isempty, &mutex1);

    usleep(2000000);
    petrolDistributor.petrol = initialFuel; //Refill petrol and change state
    pthread_cond_broadcast(&carwaiting); // Wake up any cars waiting for fuel
    pthread_mutex_unlock(&mutex1);

请注意,我在这里使用了 pthread_cond_broadcast(),因为如果将其扩展到包括多辆汽车,可能会有不止一辆在等待加油。

您的 pthread_join() 电话应该是:

pthread_join(car, NULL);
pthread_join(supply, NULL);

(pthread_join()pthread_t 作为参数,而不是 pthread_t *).