如何解决线程在等待信号后 4 次未执行 2 个不同的函数
简介
我打算通过这个程序学习 C 代码中的
此程序模拟产品 Q 和 R 的生产线:
Q 需要 1A、1B、1C,R 需要 1A、1C。
produce_Q 和produce_R 函数共享相同的资源
代码
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem_worker[2]; //Semaphores (workers)
//Current stock (initialized as MAX stock)
int stock_A = 5;
int stock_B = 3;
int stock_C = 5;
//Q production method needs 1A,1B and 1C
void *produce_Q(void *worker)
{
int w = (int) worker; //Worker id
//Wait if ther are not enough tools
while (stock_A < 1 || stock_B < 1 || stock_C < 1) {
printf("Not enough resources for worker[%d] for Q\n",w);
sem_wait(&sem_worker[w]); //Worker set to wait
sleep(4); //StackOverflow question here
printf("Resuming worker's [%d] production for Q\n",w);
}
//If there are tool to produce then
printf("Worker[%d] takes resources from pool for Q\n",w);
stock_A--;
stock_B--;
stock_C--;
printf("Stock: A=%d,B=%d,C=%d left\n",stock_A,stock_B,stock_C);
//Random wait to simulate prod
sleep(rand() % 4);
printf("Worker[%d] made a Q product\n",w);
//"Return" resources to stockpile
stock_A++;
stock_B++;
stock_C++;
printf("Worker[%d] returns stock for P product\n",w);
printf("Stock: A=%d,stock_C);
}
//R prouction method,needs 1A,1C
void *produce_R(void *worker)
{
int w = (int) worker; //Worker id
//Wait if ther are not enough tools
while (stock_A < 1 || stock_C < 1) {
printf("Not enough resources for worker[%d] for R\n",w);
sem_wait(&sem_worker[w]); //Worker set to wait
sleep(4); //Subject to change for sure
printf("Resuming worker's [%d] production for R\n",w);
}
//If there are tool to produce then
printf("Worker[%d] takes resources from pool for R\n",stock_C);
//Random wait to simulate prod
sleep(rand() % 4);
printf("Worker[%d] made a R product\n",w);
//"Return" resources to stockpile
stock_A++;
stock_B++;
stock_C++;
printf("Worker[%d] returns stock for R product\n",stock_C);
}
int main(void) {
int i;
pthread_t th[4]; //Number of threads to work with
printf("Setting sems...");
if (sem_init(&sem_worker[0],1) < 0) error();
if (sem_init(&sem_worker[1],1) < 0) error();
if (sem_init(&sem_worker[2],1) < 0) error();
if (sem_init(&sem_worker[3],1) < 0) error();
//Create threads
printf("Create threads...");
for (i = 0; i < 4; i++){
if (pthread_create(&th[i],NULL,produce_Q,(void*)i) < 0) error(); //4Q production
if (pthread_create(&th[i],produce_R,(void*)i) < 0) error(); //4R production
}
//Wait for thread death
printf("Waiting for death...");
for (i = 0; i < 4; i++){
if (pthread_join(th[i],NULL) < 0) error();
}
return 0;
}
问题
我没有得到预期的输出,即每个函数执行 4 次(4Q 和 4R),有时 A、B 或 C 资源将为 0 并且其中一个线程将等待资源可用性。
我在这里控制:
while (stock_A < 1 || stock_B < 1 || stock_C < 1) {
printf("Not enough resources for worker[%d] for Q\n",w);
}
但这还不够......我将“睡眠(4)”实现为“有效的补丁”,但这并没有解决我的主要问题:
“有些工人等待资源但不生产之后, 我在等待代码块中遗漏了什么吗?”
解决方法
您的代码有很多问题。其中一些较大的是:
-
您启动了 8 个线程,但只加入了 4 个(另见下文)。你不能加入其他四个,因为你已经覆盖了他们的线程标识符:
for (i = 0; i < 4; i++){ if (pthread_create(&th[i],NULL,produce_Q,(void*)i) < 0) error(); //4Q production if (pthread_create(&th[i],produce_R,(void*)i) < 0) error(); //4R production }
请特别注意,在每次迭代中,您都将每个新线程的线程标识符存储在同一数组元素中。如果你不加入其他四个,那么你不能相信他们会在整个程序退出时被强行终止之前完成他们的工作。
您正在使用多个独立的信号量来保护对相同共享变量的访问。这是不正确和无效的。多个资源可以被同一个信号量或互斥锁保护,但重点是防止多个线程同时访问共享变量,所以如果线程只需要锁定几个信号量中的任何一个就可以获得访问,那么没有有效的保护。
-
您必须同步所有对共享变量的访问。这包括在您的
while
循环条件下测试它们的值。 -
一旦一个线程完成对共享变量的访问,它需要用
sem_post()
解锁信号量以允许其他线程获取它。您的线程永远不会这样做。在这个模拟中,线程在声明资源之后但在“生产”他们的产品之前解锁信号量是有意义的。在这种情况下,他们会希望在返回资源之前再次锁定它,然后再释放它。 -
正如我在评论中所写,
sleep()
不是同步函数。它没有可同步播放的有效部分。但是,您可能会发现,如果没有这些调用,您的程序将无法取得进展。这是因为需要在满足条件之前暂停线程执行的程序通常应该围绕条件变量构建。这些允许线程挂起直到被通知测试条件是值得的,而不是获取所需的锁并在每一个机会测试条件。- 但是,与 pthreads 条件变量一起使用的适当锁定对象是(pthreads)互斥锁,而不是信号量。如果您想使用信号量,那么您需要一个不同的范例。
此外,你的程序有一个有点奇怪的结构。它不仅尝试在互斥量 + 条件变量更自然的情况下使用信号量,而且解决此类生产模拟问题的更典型方法将只涉及每个生产线的一个线程,每个线程执行一个循环以生成多个项目的函数.这种循环结构更适合使用信号量。它会像这样工作:
-
每个线程都有一个单独的信号量。 只有一个被初始化为1;另一个(其余的)用值 0 初始化。
-
线程被强制进入一个严格的循环序列来获取锁。为此,当每个线程退出临界区时,它会解锁下一个线程的信号量。
-
当线程完成其正常工作时,它们必须继续参与循环信号量锁定,直到所有其他线程也完成其工作。
-
因此,必须有另外一个或多个共享数据,线程可以通过这些数据确定所有工作何时完成。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。