我编写了一个小程序来查看创建线程所需的开销。
这是程序(我写得很快,所以它不是最好的):
#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
这意味着第一个线程最后完成...
所以,我的朋友们,有没有人对这种现象有可能的解释?
答案 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的正常使用,你的例子不是。