奇怪的线程执行顺序?

时间:2011-07-09 03:06:53

标签: c++ c multithreading pthreads

我编写了一个小程序来查看创建线程所需的开销。

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

#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

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

所以,我的朋友们,有没有人对这种现象有可能的解释?

4 个答案:

答案 0 :(得分:9)

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

其次,你不应该担心操作系统如何安排你的线程。

答案 1 :(得分:4)

您的代码正在打印脏数据。没有内存障碍,因此数据实际上是垃圾。最重要的是,您不必等待线程退出,因此在您启动所有线程之前很可能会终止该进程。要实现(或多或少)你想要的东西,尝试这样的事情:

#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%的多线程程序都存在线程饥饿而不是获得性能。

无论如何,祝你好运!

答案 2 :(得分:3)

正如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);
    }
}

答案 3 :(得分:2)

这高度依赖于内核调度程序实现,也可能是pthread库 - 并且永远不能保证线程执行的顺序。有很多优化措施可以加速pthreads的正常使用,你的例子不是。