【问题标题】:Pthread in C basic printC基本打印中的Pthread
【发布时间】:2016-05-09 05:48:24
【问题描述】:

我正在使用创建子线程的 Pthreads 编写 C 程序。创建子线程后,父线程应该输出两条消息:“parent:begin”,然后它应该打印“parent:done”。子线程“child:begin”和“child:done”也一样。我必须确保主线程在生成的(子)线程之前打印他的第二条消息。我必须遵循实施,但它只会以错误的顺序打印。我想我应该使用标志。任何帮助将不胜感激。

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>


volatile int done = 0;

void *child(void *arg) {
 printf("child\n");
done = 1;
 printf("child:done");
return NULL;
 }

int main(int argc, char *argv[]) {
 printf("parent: begin\n");
 pthread_t c;
 pthread_create(&c, NULL, child, NULL); // create child
 while (done == 0); // spin
 printf("parent: end\n");
 return 0;
 }

【问题讨论】:

  • 您的子线程只发出一条消息。
  • 更好的方法是使用wait 系列系统调用,而不是父系统中的繁忙循环。
  • 谢谢,我已经更新了代码,我想要实现的是确保主线程在生成的(子)线程之前打印他的第二条消息。
  • 目前:1. 父级:开始 2.子级 3.子级:完成 4.父级:结束。

标签: c multithreading pthreads pthread-join


【解决方案1】:

此时done 被两个线程在没有任何同步的情况下访问。正确的方法是使用条件变量向孩子发出父母已完成打印的信号。这会导致数据竞争

此外,main() 线程在执行之前完成了执行。在那种情况下,整个过程都会死掉。您可以调用pthread_join() 或直接使用pthread_exit() 退出主线程。

    #include <unistd.h>
    #include <stdio.h>
    #include <pthread.h>

    pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
    pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

    volatile int done = 0;

    void *child(void *arg) {
      printf("child\n");
      pthread_mutex_lock(&mutex);
      while(done == 0)
        pthread_cond_wait(&cond, &mutex);

      pthread_mutex_unlock(&mutex);
      printf("child:done");
      return NULL;
   }

    int main(int argc, char *argv[]) {
      printf("parent: begin\n");
      pthread_t c;
      pthread_create(&c, NULL, child, NULL); // create child

      pthread_mutex_lock(&mutex);
      done = 1;
      printf("parent: end\n");
      pthread_cond_signal(&cond);
      pthread_mutex_unlock(&mutex);

      pthread_exit(0);
   }

【讨论】:

  • 这个问题模棱两可,所以我想没关系。
  • @2501 I have to make sure that the main thread prints his second message before the spawned (child) thread does parent:end(第二个消息)首先被打印 child:done 被打印。 at the moment: 1. parent:begin 2.child 3.child:done 4.parent:end. parent:end 最后打印。但是 OP 显然接受了一个答案,该答案产生了与我的解释不同的东西。
  • 当他拒绝回应我(现已删除)的 cmets 以澄清问题时,我们必须辩论什么 OP 在想什么,这不是很遗憾。我通常会点击关闭/否决票,如果 OP 没有回应,我认为这是正确的回应。
  • OP 很忙。首先,感谢您对@2501 的回复。为了清楚起见,我把它写在这里:我必须实现它,以便主线程在生成的线程执行他的第二条消息之前打印他的第二条消息。谢谢。
【解决方案2】:

如果您希望父线程首先打印done,那么您应该让子线程旋转直到父线程完成。 (现在父线程正在等待子线程。)您还应该使用pthread_join 确保子线程在主线程返回之前完成:

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>


volatile int done = 0;

void *child(void *arg) {
    printf("child: begin\n");
    while (done == 0); // spin
    printf("child: done\n");
    return NULL;
}

int main(int argc, char *argv[]) {
    printf("parent: begin\n");
    pthread_t c;
    pthread_create(&c, NULL, child, NULL); // create child
    printf("parent: done\n");
    done = 1;
    pthread_join(c, NULL);
    return 0;
}

在我的机器上我得到这个输出:

parent: begin
parent: done
child: begin
child: done

【讨论】:

  • 这并不能保证 child:begin 在 parent:done 之前不会被打印。
  • @2501 - 这是真的,但根据问题中的标准,我认为只有“完成”部分很重要......?如果“child: begin”消息也需要排序,那么printf("child: begin\n");应该在旋转循环之后移动。
  • 即使这是所需的输出顺序(从 OP 的 Q 和评论中不太清楚),程序仍然是错误的,因为它包含产生 undefined 的 data race行为。因为done 正在被两个线程访问而没有任何锁。
  • @l3x - 我同意这可能不是最正确的解决方案(我宁愿使用原子代替),但它很简单,应该适用于大多数平台(编译器/硬件真的会必须竭尽全力把这个搞砸),任何更复杂的事情都可能超出任务的范围(我假设这是家庭作业)。但是,我仍然觉得我应该指出您的评论不是很有用,因为您没有说就什么行为是未定义的。 POSIX 未定义? C11? (学究要准确!)
  • @DaoWen 你不妨争辩说i = i++ + i--;“应该工作”并在大多数系统上产生一定的输出。指出数据竞争(未定义的行为)不是学究式的评论。 POSIX 没有明确说明,但是具有数据竞争的程序只能是无效的。 C11 说它是 undefined.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多