线程项目问题| c中如何等待/信号来自多个线程



我实际上在做一个个人项目,我必须做一个小程序来模拟这种行为:

有两种类型的人:村民和德鲁伊(如Asterix/Obelix)

每个村民都有一个id(一个村民唯一的数字)。它会战斗;nb_战斗;离开前的时间战场。在每次战斗之前,它必须从罐子里拿出一份魔法药水(如果罐子是空的,它必须通知德鲁伊并等待,直到罐子被填满)。

德鲁伊将等待村民召唤;然后它会把锅装满一罐的食物。当nb_refills已经完成了,德鲁伊已经用光了原料,它的线程必须停止。

参数()中给出了所有内容。/panoramix & lt; nb_villagers>& lt; pot_size>& lt; nb_fights>& lt; nb_refills>

嗯,实际上我做了70%的项目,但我有麻烦叫德鲁伊补充药剂。

村民线程的代码:

void *villager(void *args)
{
int pNb = nbF;
int id = *(int *)args;

printf("Villager %d: Going into battle!n", id);
while (pNb > 0) {
pthread_mutex_lock(&mpot);
printf("Villager %d: I need a drink... I see %d servings left.n", id, pot_size);
if (pot_size == 0) {
printf("Villager %d: Hey Pano wake up! We need more potion.n", id);
sem_wait(&test);
}
pot_size--;
pthread_mutex_unlock(&mpot);
pNb--;
printf("Villager %d: Take that roman scum! Only %d left.n", id, pNb);
}
printf("Villager %d: I’m going to sleep now.n", id);
}

WITHpNb =战斗数(我们减少)

然后是德鲁伊线程:

void *druid(void *args)
{
int sizepot = pot_size;
printf("Druid: I'm ready... but sleepy...n");
while (nb_refills > 0) {
while (pot_size != 0) {
}
sem_wait(&test);
nb_refills--;
printf("Druid: Ah! Yes, yes, I'm awake! Working on it! Beware I can only make %d more refills after this one.n", nb_refills);
pot_size = sizepot;
sem_post(&test);
}
printf("Druid: I'm out of viscum. I'm going back to... zZzn");
}

我想知道我如何才能"呼叫"。德鲁伊当"pot_size";为空(=0).

我尝试用if条件中的信号量来做:

if (pot_size == 0) {
printf("Villager %d: Hey Pano wake up! We need more potion.n", id);
sem_wait(&test);
}

(等待德鲁伊填充pot_size,然后继续程序),但我认为这不是很好。

编辑:整个代码:

#include "struct.h"
sem_t test;
pthread_mutex_t mpot;
pthread_mutex_t fill;
int nbV = 0;
int pot_size = 0;
int nbF = 0;
int nb_refills = 0;
int errorhandler(int ac, char **av)
{
if (ac != 5)
{
printf("USAGE: ./panoramix <nb_villagers> <pot_size> <nb_fights> <nb_refills> nValues must be > 0.n");
return (84);
}
if (atoi(av[1]) == 0 || atoi(av[2]) == 0 || atoi(av[3]) == 0 || atoi(av[4]) == 0)
{
printf("USAGE: ./panoramix <nb_villagers> <pot_size> <nb_fights> <nb_refills> nValues must be > 0.n");
return (84);
}
return (0);
}
void *druid(void *args)
{
int sizepot = pot_size;
printf("Druid: I'm ready... but sleepy...n");
while (nb_refills > 0) {
while (pot_size != 0) {
usleep(1000);
}
pthread_mutex_lock(&fill);
nb_refills--;
printf("Druid: Ah! Yes, yes, I'm awake! Working on it! Beware I can only make %d more refills after this one.n", nb_refills);
pot_size = sizepot;
pthread_mutex_unlock(&fill);
}
printf("Druid: I'm out of viscum. I'm going back to... zZzn");
}
void *villager(void *args)
{
int pNb = nbF;
int id = *(int *)args;

printf("Villager %d: Going into battle!n", id);
while (pNb > 0) {
pthread_mutex_lock(&mpot);
printf("Villager %d: I need a drink... I see %d servings left.n", id, pot_size);
if (pot_size == 0) {
printf("Villager %d: Hey Pano wake up! We need more potion.n", id);
}
pot_size--;
pthread_mutex_unlock(&mpot);
pNb--;
printf("Villager %d: Take that roman scum! Only %d left.n", id, pNb);
}
printf("Villager %d: I’m going to sleep now.n", id);
}
int main(int ac, char **av)
{
if (errorhandler(ac, av) == 84)
return (84);
nbV = atoi(av[1]);
pot_size = atoi(av[2]);
nbF = atoi(av[3]);
nb_refills = atoi(av[4]);
pthread_t th[nbV];
int i;
pthread_mutex_init(&mpot, NULL);
pthread_mutex_init(&fill, NULL);
sem_init(&test, 0, 1);
for (int i = 0; i < nbV; i++) {
int *a = malloc(sizeof(int));
*a = i;
if (pthread_create(&th[i], NULL, &villager, a) != 0) {
perror("Failed to create the Villagern");
}
}
pthread_create(&th[nbV], NULL, &druid, NULL);
for (int i = 0; i < atoi(av[1]); i++) {
if (pthread_join(th[i], NULL) != 0) {
perror("Failed to launch the Villagern");
}
}
sem_destroy(&test);
pthread_mutex_destroy(&mpot);
pthread_mutex_destroy(&fill);
return (0);
}
  1. 将游戏所需的所有全局变量分组到struct中,使其更容易在某个位置访问。

typedef struct {
int nbV;            // # of villagers
int nbF;            // # of fights each villager takes on
int nb_refills;     // # of potion refills that druid can make
int pot_size;       // size of potion pot
int potion_left;    // remaining potion in pot for consumption
int druid_awake;    // flag only modified by druid
int villagers_awake;
sem_t pot_sem;
pthread_mutex_t potion_mutex;
} sPanoramix_t;
sPanoramix_t pgame;
  1. druid()不应该调用sem_wait(),因为这是生产者。如果所有的村民都结束了战斗,检查他们是否都睡着了,如果他们睡着了,返回/退出。
void *druid (void *args) {
printf ("Druid: I'm ready... but sleepy...n");
pgame.druid_awake = 1;
while (pgame.nb_refills > 0) {
while (pgame.potion_left > 0) {
if (!pgame.villagers_awake) {
printf ("Druid: KILLED all of them today! Drinks are on me :-)n");
return NULL;
}
usleep (1000);
}
pgame.nb_refills--;
printf ("Druid: Ah! Yes, yes, I'm awake! Working on it! Beware I can only make %d more refills after this one.n", pgame.nb_refills);
pgame.potion_left = pgame.pot_size;
printf ("Druid: Kill those romans, potion refilled to %dn", pgame.potion_left);
sem_post (&pgame.pot_sem);
}
printf ("Druid: ALERT!! I'm out of viscum. I'm going back to... zZzn");
pgame.druid_awake = 0;    // druid is not available anymore
return NULL;
}
  1. 村民需要检查德鲁伊是否睡着了,即。已用尽所有重新填充配额。因为只有一个线程有互斥锁&没有药水可以消耗,我们可以在sem_wait()上阻塞,让德鲁伊补充;sem_post()
void *villager (void *args) {
int pNb = pgame.nbF;
int id = (unsigned long)args;
printf ("Villager %d: Going into battle!n", id);
while (pNb > 0) {
pthread_mutex_lock (&pgame.potion_mutex);
printf ("Villager %d: I need a drink... I see %d servings left.n", id, pgame.potion_left);
if (pgame.potion_left <= 0) {
if (!pgame.druid_awake) {
printf ("Villager %d: We're doomed now Pano!n", id);
pthread_mutex_unlock (&pgame.potion_mutex);
return NULL;
}
printf ("Villager %d: Hey Pano wake up! We need more potion.n", id);
sem_wait (&pgame.pot_sem);
printf ("Villager %d: Thank you PANO!n", id);
}
pgame.potion_left--;
pthread_mutex_unlock (&pgame.potion_mutex);
pNb--;
printf ("Villager %d: Take that Roman scum! Only %d left.n", id, pNb);
usleep (1000); // let other villagers take turn
}
printf ("Villager %d: KILLED my quota of Romans, I’m going to sleep now.n", id);
pthread_mutex_lock (&pgame.potion_mutex);
pgame.villagers_awake --;
pthread_mutex_unlock (&pgame.potion_mutex);
return NULL;
}
  1. 修改main():
int main (int ac, char **av) {
if (errorhandler (ac, av) == 84)
return (84);
pgame.nbV = atoi (av[1]);
pgame.villagers_awake = pgame.nbV;
pgame.pot_size = atoi (av[2]);
pgame.potion_left = pgame.pot_size;
pgame.nbF = atoi (av[3]);
pgame.nb_refills = atoi (av[4]);
pthread_t th[pgame.nbV + 1];
pthread_mutex_init (&pgame.potion_mutex, NULL);
sem_init (&pgame.pot_sem, 0, 1);
pthread_create (&th[0], NULL, druid, NULL);
usleep (1000);
for (int i = 1; i <= pgame.nbV; i++) {
if (pthread_create (&th[i], NULL, villager, (void*) (unsigned long)i) != 0)
perror ("Failed to create the Villagern");
}
for (int i = 0; i <= pgame.nbV; i++) {
if (pthread_join (th[i], NULL) != 0)
perror ("Failed pthread_join()n");
}
sem_destroy (&pgame.pot_sem);
pthread_mutex_destroy (&pgame.potion_mutex);
printf ("End of game Panoramix!n");
return (0);
}
  1. 使用strtol()代替atoi(),它给你更多的控制:如何在C中转换字符串为整数?

  2. 你可以使用pthread_detach(),如果线程没有返回任何有意义的东西,等待线程用pthread_join()

最新更新