【问题标题】:How do threads work in C? [closed]线程如何在 C 中工作? [关闭]
【发布时间】:2015-11-05 14:14:43
【问题描述】:

如何重现输出:

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

int myglobal;

void *thread_function(void *arg) {
  int i,j;
  for ( i=0; i<20; i++ ) {
    j=myglobal;
    j=j+1;
    printf(".");
    fflush(stdout);
    sleep(1);
    myglobal=j;
  }
  return NULL;
}

int main(void) {
  pthread_t mythread;
  int i;

  myglobal = 0;

  if ( pthread_create( &mythread, NULL, thread_function, NULL) ) {
    printf("error creating thread.");
    abort();
  }

  for ( i=0; i<20; i++) {
    myglobal=myglobal+1;
    printf("o");
    fflush(stdout);
    sleep(1);
  }

  if ( pthread_join ( mythread, NULL ) ) {
    printf("error joining thread.");
    abort();
  }

  printf("\nmyglobal equals %d\n",myglobal);
  exit(0);
}

输出:

o..oo..oo..oo..oo..oo..oo..oo..oo..oo..o

myglobal 等于21

问题:

有人能解释一下这个输出是如何产生的吗? 为什么不像“o.o.o.o.”那样交替使用呢?

【问题讨论】:

  • 你应该先了解线程是什么!有足够的信息可以找到。懒得看维基百科?为什么你希望他们交替执行?
  • 我期望的输出是:“o.o.o.o”等等。我不明白一个线程如何超越另一个线程。
  • 我不知道你是否理解我的问题。我将再次尝试解释:我们有两个线程。一个打印“。”并停顿一秒钟。另一个打印“o”并暂停一秒钟。怎么可能连续有两个“oo”和“..”?
  • 没有人注意到有sleep调用应该强制交替?这在我的机器上完美交替。
  • 睡眠的作用是它可能会或可能不会生成上下文切换。您无法知道其他进程执行其时间片所需的时间。所以 sleep 的意思是:“睡 1 秒或更长时间,或者什么”。 Linux(或任何操作系统)不是 RTOS。所以这里没有保证的行为。此外,这里可能存在竞争条件,因为两个线程都写入同一个变量。此外,从几个不同的线程调用 stdio 函数是有问题的做法。

标签: c multithreading pthreads posix


【解决方案1】:

在您的示例中,有两个线程同时运行。两者都在大约同时开始打印,并且都在打印之间等待大约 1 秒。您无法准确确定“。”的顺序。与“o”相比,只是随着时间的推移,它们的数量将大致相同。

如果,您添加了半秒睡眠:

usleep(500000);
for ( i=0; i<20; i++) {
  myglobal=myglobal+1;
  printf("o");
  fflush(stdout);
  sleep(1);
}

那么这两个线程将更一致地交替它们的时间,你会得到你期望的序列。但请注意,即使如此,在很长一段时间内,两个线程的时间也不同步,它们可能会漂移(并破坏“o.o.o.o.o”的完美一致性)

【讨论】:

    【解决方案2】:

    有人能解释一下这个输出是如何产生的吗?为什么不像“o.o.o.o.”那样交替使用呢?

    它们不能可靠地交替,因为您没有提供使它们这样做的机制。特别是,您对sleep() 函数的使用并不能实现该目标。这不是一个线程“超越”另一个线程的问题。相反,在每次迭代中,两个线程都可以在几乎完全相同的时间运行,并且机器似乎倾向于让上次运行的线程首先恢复。这是允许的,但不是必需的。

    依靠时间来同步线程活动是不安全的。您需要使用 IPC(管道、信号)或线程同步对象,例如信号量、互斥锁或条件变量。

    【讨论】:

      【解决方案3】:

      每一秒,你的两个线程都被唤醒并尝试打印它们各自的字符,但你不能对它们再次运行的顺序做出任何假设,在你的情况下,你似乎有:&lt;top&gt;t1 then t2&lt;top&gt;t2 then t1&lt;top&gt;t1 then t2&lt;top&gt;... 给你@987654322 @等

      在我的系统 (OSX El Capitan) 上,调度给了我:o.o.o.o.

      在我的 Solaris 上,它给出:o..oo..oo.o.o..oo..oo.o.o..oo.o..oo..oo.

      在我的 ubuntu 上:o.o..o.o.oo..o.oo.o.o.o.o.o.o.o.o.o.o.o.

      【讨论】:

      • 所以你说这是我的操作系统使用什么调度的问题?我正在使用 freeBSD 作为操作系统。
      • 是的,线程调度当然很重要!我必须在我的不同系统上进行实验。
      【解决方案4】:

      创建线程时,它会从创建它的线程继承其优先级。您还可以使用 setPriority 方法在创建线程后随时修改其优先级。在任何给定时间,当多个线程准备好执行时,运行时系统会选择具有最高优先级的 Runnable 线程来执行。只有当该线程停止、产生或变为不可运行时,较低优先级的线程才会开始执行。如果两个相同优先级的线程都在等待 CPU,调度器会任意选择其中一个来运行。所选线程一直运行,直到满足以下条件之一:

      • 更高优先级的线程变为可运行的。
      • 它产生,或者它的运行方法退出。
      • 在支持时间片的系统上,其时间分配已过期。

      然后第二个线程有机会运行,依此类推,直到解释器退出。

      【讨论】:

      • 感谢您的回答。很好的解释,但不幸的是我不能把它提到我的问题......
      • 我认为你最好了解线程是如何工作的,而不是了解这个程序是如何工作的。查找有关线程和调度策略的信息
      猜你喜欢
      • 2023-03-10
      • 2023-03-24
      • 1970-01-01
      • 2021-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-13
      • 1970-01-01
      相关资源
      最近更新 更多