【发布时间】:2020-10-28 11:30:26
【问题描述】:
我正在为an operating systems course 的作业编写代码。
This 是我正在编辑的文件。
This 是解决方案的测试代码。
注意:无需查看这些文件即可理解代码。
作业要求一种在线程之间进行通信的方式。线程有 3 种类型:male、female 和 matchmaker。
我有 3 个函数:male(thread_id)、female(thread_id) 和 matchmaker(thread_id)。
male、female 或 matchmaker 线程应该休眠,直到其他两种类型的两个线程可用。例如,如果没有单个female 线程在运行或没有单个matchmaker 线程在运行,则male 线程应该休眠。如果这三种类型都存在,matchmaker 将匹配 male 和 female 线程,然后 3 个线程应该退出。
测试代码创建了 10 个 male 线程、10 个 female 线程和 10 个 matchmaker 线程,并期望每种类型中的一个能够一起通信然后退出。
注意:处理每种类型线程的函数代码几乎相同。
我使用条件变量解决了这个问题,它工作正常。这是解决方案:
struct lock *lock = NULL;
struct cv *male_cv = NULL;
struct cv *female_cv = NULL;
struct cv *matchmaker_cv = NULL;
int male_count = 0;
int female_count = 0;
int matchmaker_count = 0;
void whalemating_init() {
lock = lock_create("whalemating lock");
male_cv = cv_create("male");
female_cv = cv_create("female");
matchmaker_cv = cv_create("matchmaker");
male_count = 0;
female_count = 0;
matchmaker_count = 0;
}
/*
* Called by the driver during teardown.
*/
void
whalemating_cleanup() {
lock_destroy(lock);
lock = NULL;
cv_destroy(male_cv);
cv_destroy(female_cv);
cv_destroy(matchmaker_cv);
male_cv = NULL;
female_cv = NULL;
matchmaker_cv = NULL;
}
void
male(uint32_t index)
{
(void)index;
/*
* Implement this function by calling male_start and male_end when
* appropriate.
*/
male_start(index);
lock_acquire(lock);
if (matchmaker_count > 0 && female_count > 0) {
cv_signal(matchmaker_cv, lock);
cv_signal(female_cv, lock);
} else {
male_count++;
cv_wait(male_cv, lock);
male_count--;
}
lock_release(lock);
male_end(index);
return;
}
void
female(uint32_t index)
{
(void)index;
/*
* Implement this function by calling female_start and female_end when
* appropriate.
*/
female_start(index);
lock_acquire(lock);
if (matchmaker_count > 0 && male_count > 0) {
cv_signal(matchmaker_cv, lock);
cv_signal(male_cv, lock);
} else {
female_count++;
cv_wait(female_cv, lock);
female_count--;
}
lock_release(lock);
female_end(index);
return;
}
void
matchmaker(uint32_t index)
{
(void)index;
/*
* Implement this function by calling matchmaker_start and matchmaker_end
* when appropriate.
*/
matchmaker_start(index);
lock_acquire(lock);
if (male_count > 0 && female_count > 0) {
cv_signal(male_cv, lock);
cv_signal(female_cv, lock);
} else {
matchmaker_count++;
cv_wait(matchmaker_cv, lock);
matchmaker_count--;
}
lock_release(lock);
matchmaker_end(index);
return;
}
这是一个使用信号量但并不总是有效的信号量(在某些运行中运行良好并在其他运行中挂起):
struct semaphore *male_sem = NULL;
struct semaphore *female_sem = NULL;
struct semaphore *matchmaker_sem = NULL;
/*
* Called by the driver during initialization.
*/
void whalemating_init() {
// sem_create(sem_name, sem_initial_value);
male_sem = sem_create("male", 0);
female_sem = sem_create("female", 0);
matchmaker_sem = sem_create("matchmaker", 0);
}
/*
* Called by the driver during teardown.
*/
void
whalemating_cleanup() {
sem_destroy(male_sem);
sem_destroy(female_sem);
sem_destroy(matchmaker_sem);
male_sem = NULL;
female_sem = NULL;
matchmaker_sem = NULL;
}
void
male(uint32_t index)
{
(void)index;
/*
* Implement this function by calling male_start and male_end when
* appropriate.
*/
male_start(index);
V(male_sem);
V(male_sem);
P(female_sem);
P(matchmaker_sem);
male_end(index);
return;
}
void
female(uint32_t index)
{
(void)index;
/*
* Implement this function by calling female_start and female_end when
* appropriate.
*/
female_start(index);
V(female_sem);
V(female_sem);
P(male_sem);
P(matchmaker_sem);
female_end(index);
return;
}
void
matchmaker(uint32_t index)
{
(void)index;
/*
* Implement this function by calling matchmaker_start and matchmaker_end
* when appropriate.
*/
matchmaker_start(index);
V(matchmaker_sem);
V(matchmaker_sem);
P(male_sem);
P(female_sem);
matchmaker_end(index);
return;
}
P 函数接受一个信号量,如果大于 0,则减少其计数,如果计数为 0,则休眠。
V 函数增加计数,如果有任何休眠线程,则唤醒。
在后一种解决方案中,每个线程都会将其信号量增加两次,因为其他两个线程中的每一个都会将其减少一次。然后在其他两个信号量上分别调用P。如果两个信号量的计数都大于 0,则函数继续执行直到结束。如果其中至少一个的计数为 0,则线程会休眠,直到该信号量的计数上升。
后一种方案有什么问题?
编辑
这个带有信号量的代码可以正常工作:
struct semaphore *male_sem = NULL;
struct semaphore *female_sem = NULL;
struct semaphore *matchmaker_sem = NULL;
/*
* Called by the driver during initialization.
*/
void whalemating_init() {
// sem_create(sem_name, sem_initial_value);
male_sem = sem_create("male", 0);
female_sem = sem_create("female", 0);
matchmaker_sem = sem_create("matchmaker", 0);
}
/*
* Called by the driver during teardown.
*/
void
whalemating_cleanup() {
sem_destroy(male_sem);
sem_destroy(female_sem);
sem_destroy(matchmaker_sem);
male_sem = NULL;
female_sem = NULL;
matchmaker_sem = NULL;
}
void
male(uint32_t index)
{
(void)index;
/*
* Implement this function by calling male_start and male_end when
* appropriate.
*/
male_start(index);
P(male_sem);
V(matchmaker_sem);
male_end(index);
return;
}
void
female(uint32_t index)
{
(void)index;
/*
* Implement this function by calling female_start and female_end when
* appropriate.
*/
female_start(index);
P(female_sem);
V(matchmaker_sem);
female_end(index);
return;
}
void
matchmaker(uint32_t index)
{
(void)index;
/*
* Implement this function by calling matchmaker_start and matchmaker_end
* when appropriate.
*/
matchmaker_start(index);
V(male_sem);
V(female_sem);
P(matchmaker_sem);
P(matchmaker_sem);
matchmaker_end(index);
return;
}
为什么这个有效而另一个无效?
【问题讨论】:
-
这与问题没有直接关系,但与程序逻辑有关:我认为
matchmaker不需要 10 个线程。matchmaker应该只有一个线程,它应该 (1) 唤醒,(2) 进行匹配,如果存在空闲对,(3) 否则,休眠... -
@ssd 感谢您的建议。不幸的是,这就是他们决定测试代码的方式。我对此无能为力。
-
@ssd 我猜这是一个关于同步 3 个线程的任务,而男/女/媒人的名字只是愚蠢的名字。如果你愿意,可以称它们为线程 A、B、C。
标签: c multithreading synchronization semaphore condition-variable