关于C++的跨平台多线程库,这里列举了一些知名的库:
其中,tinythread++是个很轻量级的,我们这里只介绍它
TinyThread++只有一个cpp文件和两个h文件,使用时,将它们放在自己的工程中一道编译。
TinyThread++的主页,可以下载这个库。下载解压,进入TinyThread++目录,主要有source和test两个子目录,前者包含TinyThread++的三个文件,后者包含三个简单的示例程序,其中test.cpp比较详细地列举了9种应用。
下面是个使用detach的thread的小例子:
#include
#include
#include
using namespace std;
using namespace tthread;
struct inputData
{
int len;
const char* data;
};
void ThreadProc(void *aArg)
{
inputData input = *((inputData*)aArg);
string s;
s.assign(input.data, input.len);
cout << "Sub thread id: " << this_thread::get_id() << " input data: " << s << endl;
}
int main(int argc, char* argv[])
{
cout << "this thread id: " << this_thread::get_id() << endl;
for(int i = 0; i < 3; ++i)
{
inputData input;
string s;
switch(i)
{
case 0:
s = "#Data0#";
break;
case 1:
s = "#Data1#";
break;
case 2:
s = "#Data2#";
break;
}
input.len = s.size();
input.data = s.c_str();
thread t(ThreadProc, &input);
t.detach();
//sleep(1);
}
cout << "..................." << endl;
while(1)
sleep(1);
return 0;
}
其目的是,在主线程中创建3个从线程,分别传给它们不同的inputData输入参数,主要是输入的字符串内容不一样。希望在每个从线程中输出传入的字符串,然后自行退出。
实际输出的一种结果是:
this thread id: 1
Sub thread id: 2 input data: #Data1#
...................
Sub thread id: 3 input data: #Data2#
Sub thread id: 4 input data: #Data2#
按照我们期望的,2号线程,输出的input data部分应该是 #Data1#,3号,应该是#Data1#,实际得到的结果和设想的不一致。
调试发现,每次走到第16行的时候,指针aArg的值是一样的!即,22行申明的、44行传给ThreadProc函数的临时变量input,每次都在同样的内存空间中分配。于是,3个从线程,都从同一块内存区域读取输入参数值。这就造成,有可能前一个线程还没来得及从那段内存中读取数据,那段内存就在创建下一个从线程的时候被重新赋值(覆盖)了。
对应上面的实际输出,覆盖操作就是:
2号线程还没来得及读,就被为3号线程而做的赋值操作给覆盖了,造成2号线程本该输出#Data0#的,却输出了#Data1#;
3号线程还没来得及读,就被为4号线程而做的赋值操作给覆盖了,造成3号线程本该输出#Data1#的,却输出了#Data2#。
事实上,如果我们放开46行的sleep操作,就不会出现上面的问题了,因为两个相邻的“创建从线程”的操作之间sleep了1秒钟,这段时间足以让前一个从线程在临时变量input未被覆盖的情况下从中读取它想要的数据!
输入给从线程的数据不使用栈上的临时变量,而是在堆上分配空间,每次都new出新的input变量(对应不同的内存空间),各个从线程从各自的堆空间中读取自己想要的数据,相互不干扰。从线程使用完毕堆上的数据后,自己将这些数据delete掉,然后自行退出。代码如下:
#include
#include
#include
#include
using namespace std;
using namespace tthread;
struct inputData
{
int len;
char* data;
};
void ThreadProc(void *aArg)
{
inputData input = *((inputData*)aArg);
string s;
s.assign(input.data, input.len);
cout << "Sub thread id: " << this_thread::get_id() << " input data: " << s << endl;
delete [] input.data;
delete aArg;
}
int main(int argc, char* argv[])
{
cout << "this thread id: " << this_thread::get_id() << endl;
for(int i = 0; i < 3; ++i)
{
inputData *input = new inputData;
input->data = new char[20];
input->len = strlen("#Data0");
switch(i)
{
case 0:
strcpy(input->data, "#Data0#");
break;
case 1:
strcpy(input->data, "#Data1#");
break;
case 2:
strcpy(input->data, "#Data2#");
break;
}
thread t(ThreadProc, (void*)input);
t.detach();
}
cout << "..................." << endl;
while(1)
sleep(1);
return 0;
}
本示例改正后的工程在这里
thread::~thread()
{
if(joinable())
std::terminate();
}
如果是joinable的,就立即销毁该线程相关的资源;否则,什么也不做。