简体   繁体   English

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

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

I am making multithread program using pthreads. 我正在使用pthreads编写多线程程序。 The idea is simple: 这个想法很简单:

  • Car (thread) 汽车(螺纹)
  • Petrol supply (thread) 汽油供应(螺纹)
  • Petrol station (resource) 加油站(资源)

Both car and petrol station have some fuel capacity and after car is out of fuel needs to visit petrol station. 汽车和加油站都具有一定的燃料容量,汽车用完燃料后需要前往加油站。 After petrol station is out of fuel, petrol supply thread runs and refills resource. 加油站用完燃料后,加油口运行并重新加油。 Everything seems to be fine excluding that I have to use pthread_exit instead of pthread_join to wait for threads in main function and sometimes double cout for the same car occurs: "-----End of fuel-----" . 一切似乎是罚款不包括我不得不使用pthread_exit ,而不是pthread_join等待中的主要功能,有时双线程cout为同一辆车出现: "-----End of fuel-----" Am I doing it right? 我做对了吗?

Structs and some global variables: 结构和一些全局变量:

#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;
};

Threads: 线程数:

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);
    }
}

Main: 主要:

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;
}

Output example: 输出示例:

-----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
(...)

And the question is why does output looks like that? 问题是为什么输出看起来像这样? Sometimes five iterations are fine and sixth shows double message. 有时可以进行五次迭代,而第六次则显示两次消息。 And what is wrong with join? 加入有什么问题? Thanks for advices. 感谢您的建议。

The car can show "End of fuel" multiple times because if it finds the petrolDistributor is nearly empty it doesn't wait - it goes around outer the while loop again, without refuelling itself. 这辆车可以多次显示“燃料用尽”,因为如果发现petrolDistributor快要空了,它就不会等待-它再次在while循环外旋转,而无需加油。

What you should be doing here is having the car wait on a condition variable, if it finds the petrolDistributor with insufficient fuel to for the car to refuel. 如果它发现petrolDistributor的燃料不足以供汽车加油,那么您应该在这里让汽车等待条件变量。 It shouldn't proceed until the petrolDistributor has been refuelled: 在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);

I've used a new conditiona variable carwaiting here. 我用了一个新的变量conditiona carwaiting这里。 Note that the petrolDistributor.isEmpty boolean is unnecessary - that predicate is just petrolDistributor.petrol < 30 . 请注意,不需要petrolDistributor.isEmpty布尔值-该谓词只是petrolDistributor.petrol < 30

The petrolDistributor needs to signal any waiting cars after it refills the station: 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);

Note I've used pthread_cond_broadcast() here, because if you extend this to include multiple cars, more than one might be waiting for fuel. 注意,我在这里使用了pthread_cond_broadcast() ,因为如果将其扩展为包括多辆汽车,则可能有多个汽车在等待加油。

Your pthread_join() calls should just be: 您的pthread_join()调用应该只是:

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

( pthread_join() takes a pthread_t as argument, not pthread_t * ). pthread_join()pthread_t作为参数,而不是pthread_t * )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM