执行两个或多个相同类型的线程时出现问题 - Pthread C
Problem in executing two or more threads of the same type - Pthread C
我需要使用 pthreads C 库编写一个程序来处理线程。任务的文字说:
There is a corridor that has a single lane for two directions and
there are two types of employees who will cross the corridor to reach
the opposite side of it. There are type 1 employees who go from left
to right and type 2 employees who go from right to left. In this
corridor there is an attendant who cleans this corridor when no one
passes through it. When cleaning the corridor, the employees of both
sides wait for it to end, otherwise, if the corridor is occupied, the
employee says he cannot clean and go to sleep 1 second.
如果在执行程序时我想模拟两个或更多相同类型的员工通过,在某种意义上,当 X 类型的员工在走廊中时,该类型的一名或更多其他员工到达并想利用已经获得的第一个通行证的许可,我该怎么办?
到目前为止,这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
//global variables
int c1, c2; //counters for imp1, imp2
pthread_mutex_t m1, m2;
sem_t corridor;
double clean = 0.5;
//implementation thread attendant
void *attendant(void *arg){
sleep(1); //rest 1 seconds
if (c1 == 0 && c2 == 0) {
sem_wait(&corridor);
printf("I'm starting to clean up\n");
sleep(clean);
printf("I finished cleaning\n");
sem_post(&corridor);
} else {
printf("I can't clean, the corridor is busy\n");
}
return NULL;
}
//thread employee type 1
void *emp1(void *arg) {
printf("I'm the number %d of em1\n", c1);
pthread_mutex_lock(&m1); //beginning critical section
c1++; //it increases to signal the presence of a thread of the same type that wants to enter the corridor
if (c1 == 1){ //the thread is the only one in the corridor. Can pass
printf ("I am the first of my group emp1\n");
sem_wait(&corridor); //takes possession of the corridor
}
pthread_mutex_unlock(&m1); //allows other threads of the same type to pass in the corridor since it was the first in his group. End of critical section
// invents "passage" function
pthread_mutex_lock(&m1); //beginning of the critical section. Once crossed the corridor, the variable c1 is modified. A mutex is used to avoid inconsistency
c1--;
if (c1 == 0) {
printf("I am the last of my group emp1\n");
sem_post(&corridor);
} //if c1 == 0, it is the last thread imp1 and releases the corridor
pthread_mutex_unlock(&m1); //end critical section
return NULL;
}
//thread employee type 2
void *emp2(void *arg){
printf("I'm the number %d of emp2\n", c2);
pthread_mutex_lock(&m2); //beginning critical section
c2++; //it increases to signal the presence of a thread of the same type that wants to enter the corridor
if (c2 == 1) { // the thread is the only one in the corridor. Can pass
printf("I am the first of my group emp2\n");
sem_wait(&corridor); //takes possession of the corridor
}
pthread_mutex_unlock(&m2); //allows other threads of the same type to pass in the corridor since it was the first in his group. End of critical sectionritica
// invents "passage" function
pthread_mutex_lock(&m2); //beginning of the critical section. Once crossed the corridor, the variable c1 is modified. A mutex is used to avoid inconsistency
c2--;
if (c2 == 0){
printf ("I am the last of my group emp2\n");
sem_post(&corridor);
}//if c1 == 0, it is the last thread imp1 and releases the corridor
pthread_mutex_unlock(&m2); //end critical section
return NULL;
}
int main(int argc, char const *argv[]) {
//pthread_t emp1, emp2, attendant;
pthread_t idt;
int r; //var random to create thread emp1 or emp2
int i; //index
//variable initialization
c1 = c2 = 0;
pthread_mutex_init(&m1, NULL);
pthread_mutex_init(&m2, NULL);
sem_init(&corridor,0,1);
pthread_create(&idt, NULL, attendant, NULL);
while (i < 40){
sleep(1);
r = rand() % 2;
if (r == 0) {
printf("Employee creation 1\n");
pthread_create(&idt,NULL,emp1,NULL);
} else {
printf("Employee creation 2\n");
pthread_create(&idt,NULL,emp2,NULL);
}
i++;
pthread_join(idt, NULL);
}
return 0;
}
概论
为了落实
while an employee of type X is in the corridor, one or more additional
employees of that type arrive and want to take advantage of the
permission to pass already acquired for the first one
,你首先需要让这种情况有可能出现。目前,在任何给定时间您永远不会有超过一个 emp1
或 emp2
线程(组合),因为您在开始另一个线程之前加入了每个线程。我认为对于这个模拟,除了随机员工类型之外,你还想在员工之间实现随机延迟,启动所有具有这些延迟的员工线程,然后只有在他们拥有 all[=87 之后才加入他们=] 已启动。
此外,您必须实施某种穿越走廊的计时,至少有时比员工之间的延迟时间长,否则您仍然不太可能让一名员工到达而另一名员工在走廊中。
完成后,您需要一些模拟通行许可的东西,或者更有效地模拟当前在走廊中的人。此外,您需要以允许线程 阻塞 的方式执行此操作,直到它们至少有机会继续进行。
虽然信号量可以很好地用于某些线程同步问题,但需要线程轮流或获得某些有限事物的所有权的情况通常需要一个共享变量来表示拥有的事物/回合,一个互斥锁保护访问该变量和一个条件变量帮助线程等待它们继续的机会。
实现方式
您基本上需要跟踪两件事:
当前拥有走廊的员工类型(类型 1,类型 2,或服务员)
enum { ATTENDANT, TYPE1, TYPE2 } corridor_owner;
,以及
走廊目前有多少员工。
int corridor_occupancy;
此外,所有线程都需要依赖同一个互斥锁来保护对这些数据的访问
pthread_mutex_t corridor_mutex = PTHREAD_MUTEX_INITIALIZER;
他们同样需要一份共同的简历
pthread_cond_t corridor_cv = PTHREAD_COND_INITIALIZER;
有了这个,这里有一个相当好的解决问题的方法:
当类型1或2的员工(线程)想要进入走廊时,他们必须遵循以下程序:
- 获取互斥锁。
- 检查走廊当前是否由不同类型的员工拥有并且已经被占用:
- 如果是,等待 CV,等待返回后,重新开始步骤 (2);
- 如果不是,请为其员工类型声明走廊(可能是多余的)并增加走廊占用计数。
- 释放互斥体
请注意,这允许同一类型的多名员工同时通过走廊。
当服务员要进入走廊时,它遵循不同的程序:
- 获取互斥锁。
- 检查走廊当前是否由不同类型的员工拥有并且已经被占用:
- 如果是,先释放mutex,然后sleep一秒,然后回到步骤(1);
- 如果不是,则为其员工类型申请走廊,增加走廊占用计数,然后释放互斥量。
当任何类型的员工离开走廊时,它必须
- 获取互斥量
- 减少占用计数
- 如果占用计数为零,则唤醒所有等待 CV 的线程
- 释放互斥量
此外,当服务员线程离开走廊时,它应该休眠一段时间,然后循环回来尝试再次清洁——正如您目前实施的那样,它只清洁一次。您还需要实现某种信号以使随行线程停止,或者使其成为守护线程(而不是尝试加入它)。
我需要使用 pthreads C 库编写一个程序来处理线程。任务的文字说:
There is a corridor that has a single lane for two directions and there are two types of employees who will cross the corridor to reach the opposite side of it. There are type 1 employees who go from left to right and type 2 employees who go from right to left. In this corridor there is an attendant who cleans this corridor when no one passes through it. When cleaning the corridor, the employees of both sides wait for it to end, otherwise, if the corridor is occupied, the employee says he cannot clean and go to sleep 1 second.
如果在执行程序时我想模拟两个或更多相同类型的员工通过,在某种意义上,当 X 类型的员工在走廊中时,该类型的一名或更多其他员工到达并想利用已经获得的第一个通行证的许可,我该怎么办?
到目前为止,这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
//global variables
int c1, c2; //counters for imp1, imp2
pthread_mutex_t m1, m2;
sem_t corridor;
double clean = 0.5;
//implementation thread attendant
void *attendant(void *arg){
sleep(1); //rest 1 seconds
if (c1 == 0 && c2 == 0) {
sem_wait(&corridor);
printf("I'm starting to clean up\n");
sleep(clean);
printf("I finished cleaning\n");
sem_post(&corridor);
} else {
printf("I can't clean, the corridor is busy\n");
}
return NULL;
}
//thread employee type 1
void *emp1(void *arg) {
printf("I'm the number %d of em1\n", c1);
pthread_mutex_lock(&m1); //beginning critical section
c1++; //it increases to signal the presence of a thread of the same type that wants to enter the corridor
if (c1 == 1){ //the thread is the only one in the corridor. Can pass
printf ("I am the first of my group emp1\n");
sem_wait(&corridor); //takes possession of the corridor
}
pthread_mutex_unlock(&m1); //allows other threads of the same type to pass in the corridor since it was the first in his group. End of critical section
// invents "passage" function
pthread_mutex_lock(&m1); //beginning of the critical section. Once crossed the corridor, the variable c1 is modified. A mutex is used to avoid inconsistency
c1--;
if (c1 == 0) {
printf("I am the last of my group emp1\n");
sem_post(&corridor);
} //if c1 == 0, it is the last thread imp1 and releases the corridor
pthread_mutex_unlock(&m1); //end critical section
return NULL;
}
//thread employee type 2
void *emp2(void *arg){
printf("I'm the number %d of emp2\n", c2);
pthread_mutex_lock(&m2); //beginning critical section
c2++; //it increases to signal the presence of a thread of the same type that wants to enter the corridor
if (c2 == 1) { // the thread is the only one in the corridor. Can pass
printf("I am the first of my group emp2\n");
sem_wait(&corridor); //takes possession of the corridor
}
pthread_mutex_unlock(&m2); //allows other threads of the same type to pass in the corridor since it was the first in his group. End of critical sectionritica
// invents "passage" function
pthread_mutex_lock(&m2); //beginning of the critical section. Once crossed the corridor, the variable c1 is modified. A mutex is used to avoid inconsistency
c2--;
if (c2 == 0){
printf ("I am the last of my group emp2\n");
sem_post(&corridor);
}//if c1 == 0, it is the last thread imp1 and releases the corridor
pthread_mutex_unlock(&m2); //end critical section
return NULL;
}
int main(int argc, char const *argv[]) {
//pthread_t emp1, emp2, attendant;
pthread_t idt;
int r; //var random to create thread emp1 or emp2
int i; //index
//variable initialization
c1 = c2 = 0;
pthread_mutex_init(&m1, NULL);
pthread_mutex_init(&m2, NULL);
sem_init(&corridor,0,1);
pthread_create(&idt, NULL, attendant, NULL);
while (i < 40){
sleep(1);
r = rand() % 2;
if (r == 0) {
printf("Employee creation 1\n");
pthread_create(&idt,NULL,emp1,NULL);
} else {
printf("Employee creation 2\n");
pthread_create(&idt,NULL,emp2,NULL);
}
i++;
pthread_join(idt, NULL);
}
return 0;
}
概论
为了落实
while an employee of type X is in the corridor, one or more additional employees of that type arrive and want to take advantage of the permission to pass already acquired for the first one
,你首先需要让这种情况有可能出现。目前,在任何给定时间您永远不会有超过一个 emp1
或 emp2
线程(组合),因为您在开始另一个线程之前加入了每个线程。我认为对于这个模拟,除了随机员工类型之外,你还想在员工之间实现随机延迟,启动所有具有这些延迟的员工线程,然后只有在他们拥有 all[=87 之后才加入他们=] 已启动。
此外,您必须实施某种穿越走廊的计时,至少有时比员工之间的延迟时间长,否则您仍然不太可能让一名员工到达而另一名员工在走廊中。
完成后,您需要一些模拟通行许可的东西,或者更有效地模拟当前在走廊中的人。此外,您需要以允许线程 阻塞 的方式执行此操作,直到它们至少有机会继续进行。
虽然信号量可以很好地用于某些线程同步问题,但需要线程轮流或获得某些有限事物的所有权的情况通常需要一个共享变量来表示拥有的事物/回合,一个互斥锁保护访问该变量和一个条件变量帮助线程等待它们继续的机会。
实现方式
您基本上需要跟踪两件事:
当前拥有走廊的员工类型(类型 1,类型 2,或服务员)
enum { ATTENDANT, TYPE1, TYPE2 } corridor_owner;
,以及
走廊目前有多少员工。
int corridor_occupancy;
此外,所有线程都需要依赖同一个互斥锁来保护对这些数据的访问
pthread_mutex_t corridor_mutex = PTHREAD_MUTEX_INITIALIZER;
他们同样需要一份共同的简历
pthread_cond_t corridor_cv = PTHREAD_COND_INITIALIZER;
有了这个,这里有一个相当好的解决问题的方法:
当类型1或2的员工(线程)想要进入走廊时,他们必须遵循以下程序:
- 获取互斥锁。
- 检查走廊当前是否由不同类型的员工拥有并且已经被占用:
- 如果是,等待 CV,等待返回后,重新开始步骤 (2);
- 如果不是,请为其员工类型声明走廊(可能是多余的)并增加走廊占用计数。
- 释放互斥体
请注意,这允许同一类型的多名员工同时通过走廊。
当服务员要进入走廊时,它遵循不同的程序:
- 获取互斥锁。
- 检查走廊当前是否由不同类型的员工拥有并且已经被占用:
- 如果是,先释放mutex,然后sleep一秒,然后回到步骤(1);
- 如果不是,则为其员工类型申请走廊,增加走廊占用计数,然后释放互斥量。
当任何类型的员工离开走廊时,它必须
- 获取互斥量
- 减少占用计数
- 如果占用计数为零,则唤醒所有等待 CV 的线程
- 释放互斥量
此外,当服务员线程离开走廊时,它应该休眠一段时间,然后循环回来尝试再次清洁——正如您目前实施的那样,它只清洁一次。您还需要实现某种信号以使随行线程停止,或者使其成为守护线程(而不是尝试加入它)。