【问题标题】:Program stops during threading线程期间程序停止
【发布时间】:2012-11-09 06:18:44
【问题描述】:

所以,我正在为同时运行 4 个线程的类编写程序。我的程序运行良好,除了它在运行时停止的事实。我不确定这是否与我设置 pthread_cond_wait 的方式有关,或者是否与其他原因有关。我已经多次手动跟踪程序,但找不到解释。
这是我的代码:

#include <stdio.h>
#include <pthread.h>
#include <math.h>
#include <stdlib.h>

//#define TENP .1
//#define FIFTP .15

void *tenPercentA();
void *tenPercentB();
void *fiftPercentC();
void *fiftPercentD();

pthread_cond_t aPirate;
pthread_cond_t bPirate;
pthread_cond_t cPirate;
pthread_cond_t dPirate;
pthread_mutex_t mutex;
int pearls = 1000;

int main()
{
        pthread_t tid;

        pthread_setconcurrency(4);
        pthread_create(&tid, NULL, (void *(*)(void *))tenPercentA, NULL);
        pthread_create(&tid, NULL, (void *(*)(void *))tenPercentB, NULL);
        pthread_create(&tid, NULL, (void *(*)(void *))fiftPercentC, NULL);
        pthread_create(&tid, NULL, (void *(*)(void *))fiftPercentD, NULL);

        pthread_exit(0);
}

void *tenPercentA(){
        int totalA = 0;
        double tempA = 0;

        while(pearls > 0){
                pthread_mutex_lock(&mutex);
                if(pearls > 0){
                        tempA = pearls * .1;
                        tempA = ceil(tempA);
                        totalA = totalA + tempA;
                        pearls = pearls - tempA;
                        printf("Pirate A stole %1.1f pearls.\n", tempA);
                        printf("Pirate A's total: %d\n", totalA);
                        sleep(1);
                        pthread_cond_broadcast (&bPirate);
                        pthread_cond_broadcast (&cPirate);
                        pthread_cond_broadcast (&dPirate);
                        tempA = 0.0;
                }
                else{
                        printf("No more pearls!\n");
                        exit(0);
                }
                pthread_mutex_unlock(&mutex);
                pthread_cond_wait (&aPirate, &mutex);
        }
}

void *tenPercentB(){
        int totalB = 0;
        double tempB = 0;

        while(pearls > 0){
                pthread_mutex_lock(&mutex);
                if(pearls > 0){
                        tempB = pearls * .1;
                        tempB = ceil(tempB);
                        totalB = totalB + tempB;
                        pearls = pearls - tempB;
                        printf("Pirate B stole %1.1f pearls.\n", tempB);
                        printf("Pirate B's total: %d\n", totalB);
                        sleep(1);
                        pthread_cond_broadcast (&aPirate);
                        pthread_cond_broadcast (&cPirate);
                        pthread_cond_broadcast (&dPirate);
                        tempB = 0.0;
                }
                else{
                        printf("No more pearls!\n");
                        exit(0);
                }
                pthread_mutex_unlock(&mutex);
                pthread_cond_wait (&bPirate, &mutex);
        }
}


void *fiftPercentC(){
        int totalC = 0;
        double tempC = 0;

        while(pearls > 0){
                pthread_mutex_lock(&mutex);
                if(pearls > 0){
                        tempC = pearls * .15;
                        tempC = ceil(tempC);
                        totalC = totalC + tempC;
                        pearls = pearls - tempC;
                        printf("Pirate C stole %1.1f pearls.\n", tempC);
                        printf("Pirate C's total: %d\n", totalC);
                        sleep(1);
                        pthread_cond_broadcast (&bPirate);
                        pthread_cond_broadcast (&aPirate);
                        pthread_cond_broadcast (&dPirate);
                        tempC = 0.0;
                }
                else{
                        printf("No more pearls!\n");
                        exit(0);
                }
                pthread_mutex_unlock(&mutex);
                pthread_cond_wait (&cPirate, &mutex);
        }

}

void *fiftPercentD(){
        int totalD = 0;
        double tempD = 0;

        while(pearls > 0){
                pthread_mutex_lock(&mutex);
                if(pearls > 0){
                        tempD = pearls * .15;
                        tempD = ceil(tempD);
                        totalD = totalD + tempD;
                        pearls = pearls - tempD;
                        printf("Pirate D stole %1.1f pearls.\n", tempD);
                        printf("Pirate D's total: %d\n", totalD);
                        sleep(1);
                        pthread_cond_broadcast (&bPirate);
                        pthread_cond_broadcast (&cPirate);
                        pthread_cond_broadcast (&aPirate);
                        tempD = 0.0;
                }
                else{
                        printf("No more pearls!\n");
                        exit(0);
                }
                pthread_mutex_unlock(&mutex);
                pthread_cond_wait (&dPirate, &mutex);
        }

}

下面是它在运行时执行的一些示例输出:

Pirate A stole 100.0 pearls.
Pirate A's total: 100
Pirate B stole 90.0 pearls.
Pirate B's total: 90
Pirate C stole 122.0 pearls.
Pirate C's total: 122

我唯一可以解释的想法是,当 CPU 调度程序有两个线程准备好背靠背运行时,程序会卡住。例如(在调度队列中):A |乙| C | C | D. 有什么建议吗?

【问题讨论】:

  • 不一定相关,但您可能需要在 pthread_cond_wait 上查看您的文档。我看到您在等待之前立即解锁互斥锁,这是多余的。等待将为您解锁。同样,在从 pthread_cond_wait 返回时,互斥锁被锁定,从而使您在冗余之后立即重新锁定。我建议您查看您的 pthreads 书(或者我可能需要,因为它已经有一段时间了)。
  • “我的程序运行良好,除了它在运行时停止”——这听起来并不完美……
  • 现在我看着它,反正没关系,因为我看不到 pthread_cond_init 甚至 创建 那些条件变量,所以它不像任何等待无论如何都要工作。
  • 条件 init 位于程序的顶部。 pthread_cond_t 创建一个等待条件。
  • 对于小奇迹很好,因为我刚刚下载了上面的源代码,编译了它,第一个 pthread_mutex_lock 调用失败,错误为 22 (EINVAL),这正是互斥对象应该返回的内容无效。仅仅声明它们是不够的;它们需要以一种或另一种方式初始化。这些不是。

标签: c multithreading unix


【解决方案1】:
 while(pearls > 0){
     pthread_mutex_lock(&mutex);
     if(pearls > 0){
          <do some stuff>

     } else {
           print "all done";
     }                
     pthread_mutex_unlock(&mutex);
     pthread_cond_wait (&bPirate, &mutex);
 }

因此,如果所有海盗都在 pthread_condition_wait 等待,那么当最后一个海盗偷走最后的珍珠时,您可能会发现珍珠 == 0 并退出循环。现在,您将永远不会打印所有完成的条件。并且您将退出程序而不会打印任何内容。

这就是你的程序停止并且不打印任何内容的原因。

编辑:(以上仍然正确,但不是您目前看到的问题) 来自http://linux.die.net/man/3/pthread_cond_wait

它们应该被调用线程锁定的互斥锁或未定义的行为结果调用

这些函数以原子方式释放互斥体

成功返回后,互斥体将被锁定并归调用线程所有

So what you want is:
pthread_mutex_lock(&mutex);
while (pearls > 0) {
    <do your thing>
    <signal other threads>
    pthread_cond_wait(&mutex);
}

【讨论】:

  • 但是我的程序正在打印数据。它只是停止执行中途,原因我无法完全收集。我在上面列出了一些示例输出,并且它停止的地方程序由于某种原因暂停了。我唯一能想到的是调度程序已将两个线程放在队列中以背靠背执行,并且由于我只释放所有其他 3 个线程的等待,我认为这可能是它暂停的原因。但我无法证实这一点。
  • 所以它挂起但不退出?因为你说它退出了......所以这就是我试图解释的行为。
  • "除了它在运行时停止的事实。"它正在暂停,而不是退出程序。抱歉,我应该说得更清楚。
【解决方案2】:

你的程序有很多问题。

1.- pthread_cond_wait without lock:就像 dave 已经指出的那样,您应该在互斥锁锁定的情况下调用它。否则你有未定义的行为(这总是不好的)。

例子:

pthread_mutex_lock(&mutex);
while (!conditionMet) {
  //..
  pthread_cond_wait(&cond, &mutex);
}
pthread_mutex_unlock(&mutex);

2.- 访问不受互斥体保护的变量:您正在线程中访问变量pearls,而没有使用互斥体保护访问(在while(pearls&gt;0) 中)。另一个线程可能正在写入它。尽管访问很可能是原子的,但不能保证。

3.- 在线程中退出(0)。 exit() 导致正常的程序终止发生。它猜测,这不是您在线程函数中想要的。只需使用return 退出线程即可。

4.- pthread_exit(0);在 main() 中。 pthread_exit() 函数终止调用线程。在 main 结束时,您应该等待所有线程首先终止。为此使用pthread_join(每个线程都需要一个pthread_t)。然后正常返回退出程序。

在进一步搜索之前,您应该先解决所有这些问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-21
    • 2019-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-06
    相关资源
    最近更新 更多