线程如何在 C 中工作?

How do threads work in C?

如何重现输出:

#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 equals21

问题:

谁能解释一下这个输出是如何产生的? 他们为什么不像 "o.o.o.o." 那样互相交替?

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

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

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

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

如果,你加了半秒睡眠:

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

然后这两个线程将更一致地交替它们的时间,并且您将获得您期望的顺序。但请注意,即便如此,在很长一段时间内,两个线程的时间并不同步,它们可能会漂移(并破坏 "o.o.o.o.o" 的完美一致性)

Can someone explain how this output is generated? Why dont they alternate with one another like "o.o.o.o."?

它们不能可靠地交替,因为您没有提供让它们这样做的机制。特别是,您对 sleep() 函数的使用并没有实现 objective。这不是一个线程 "overtaking" 另一个线程的问题。相反,在每次迭代中,两个线程几乎在同一时间都符合 运行 的条件,并且机器似乎倾向于让最后 运行ning 的线程先恢复。这是允许的,但不是必需的。

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

每一秒,你的两个线程都会被唤醒并尝试打印它们各自的字符,但是你不能再对它们的顺序做出任何假设运行,在你的情况下你似乎有:<top>t1 then t2<top>t2 then t1<top>t1 then t2<top>... 这给你 o..oo..o

在我的系统 (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.