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 *
).
我正在使用 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 *
).