奇怪的线程执行顺序

Weird thread execution order?

本文关键字:执行 顺序 线程      更新时间:2023-10-16

我写了一个小程序来看看创建一个线程有多少开销。

程序如下(我写得很快,所以不是最好的):

#include <iostream>
#include <pthread.h>
void * lala(void * cake) {
 int * hi = (int *)cake;
 std::cout << *hi << 'n';
}
int main(void) {
 pthread_t thread;
 for (int i = 0;i < 10000;i = i + 1) {
  pthread_create(&thread,0,lala,&i);
 }
}

它基本上启动10000个线程并传递它们的线程号,每个线程输出它的线程号。

每次运行程序时输出都会改变,但是我注意到有一部分从未改变:

在输出的最后,我总是发现这样:

...
9994
9995
9996
9997
9998
9999
0

这意味着第一个线程最后完成…

那么,我的朋友们,有人对这一现象有什么可能的解释吗?

首先,将一个局部变量的地址传递给线程,这个地址是不断变化的。因此,当线程有时间读取它时,i的内容已经被更改了。为什么你不能通过i而不是&i,其中变量只是4字节(即适合指针)?

其次,你不应该关心OS如何调度你的线程。

您的代码正在打印脏数据。没有内存屏障,所以数据实际上是垃圾。最重要的是,您不需要等待线程退出,因此很有可能在启动所有线程之前终止进程。为了达到(或多或少)你想要的,试着这样做:

#include <iostream>
#include <pthread.h>
void * lala(void * cake) {
 int * hi = (int *)cake;
 std::cout << *hi << 'n';
}
int main(void) {
 int data[10000];
 pthread_t t[sizeof (data) / sizeof (data[0])];
 for (int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
 {
   data[i] = i;
 }
 for (int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
 {
  pthread_create(&t[i], 0, lala, &data[i]);
 }
  for (int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
 {
  pthread_join (t[i], NULL);
 }
}

是的,CPU不是CUDA。创建线程是非常非常昂贵的。通常您最好使用单线程应用程序,除非您确实知道自己在做什么。我所看到的95%的多线程程序都在遭受线程饥饿而不是提高性能。

不管怎样,祝你好运!

正如Ajay指出的那样,您正在传递一个指向本地变量的指针,该变量一直在更改,一旦它超出范围(当for结束时),对它的访问是未定义的行为。

无论如何,您应该将指向堆分配变量的指针传递给线程。你可以用malloc()new。例如:

void * lala(void * cake) {
    int hi = *(static_cast<int *>(cake));
    delete cake; //we don't need it anymore, delete to avoid a leak
    std::cout << hi << 'n';
}
int main(void) {
    pthread_t thread;
    for (int i = 0;i < 10000;i = i + 1) {
        int * pie = new int;
        *pie = i;
        pthread_create(&thread,0,lala,pie);
    }
}

这高度依赖于内核调度器的实现,也可能依赖于pthread库——并且线程的执行顺序永远无法保证。有很多优化是为了加快pthread的正常使用,而您的示例不是这样。