还是先看一段非多线程的程序。我们用TestClass1表示在线程中创建的对象类,用TestClass2表示与创建线程的操作在同一定义域(也就是同一对{}之中的)的局部变量的对象类。
之所以提出TestClass2这种类,是因为在实际编程中我们会遇到这种情况:我们不可预知这个类何时创建以及创建多少;这个类的对象是一个新线程的参数。比如,在sokcet中的TCP server端就会有这种情况:如果每一个新连接的client都用创建一个新的线程去处理,我们不可预知在什么时候会有多少客户端连过来。
我们先观察没有多线程的时候对象的生命周期:
#include <iostream>
#include "windows.h"
class TestClass1{
private:
int x;
public:
explicit TestClass1(int to_x):x(to_x)
{}
~TestClass1()
{
std::cerr << "destruction: 1." << std::endl;
}
void show() const
{
std::cerr << x << std::endl;
}
};
class TestClass2{
private:
int* pX;
public:
explicit TestClass2(int to_x)
{
pX = new int;
*pX = to_x;
}
~TestClass2()
{
delete pX;
std::cerr << "destruction: 2." << std::endl;
}
const int& value() const
{
return *pX;
}
};
DWORD WINAPI thread_func(LPVOID pN)
{
Sleep(200);
TestClass1 test((*((TestClass2*)pN)).value());
test.show();
return 0;
}
int main(int argc, char* argv[])
{
for (int i = 0; i < 3; ++i) {
TestClass2 n(5);
thread_func((LPVOID)&n);
std::cerr << "loop: " << i+1 << std::endl;
}
Sleep(2000);
std::cout << "main() ok." << std::endl;
return 0;
}
这是标准的C++模式,对象的生命周期是可以预见的:
5
destruction: 1.
loop: 1
destruction: 2.
5
destruction: 1.
loop: 2
destruction: 2.
5
destruction: 1.
loop: 3
destruction: 2.
main() ok.
请按任意键继续. . .
如果我们改成线程调用:
#include <iostream>
#include "windows.h"
class TestClass1{
private:
int x;
public:
explicit TestClass1(int to_x):x(to_x)
{}
~TestClass1()
{
std::cerr << "destruction: 1." << std::endl;
}
void show() const
{
std::cerr << x << std::endl;
}
};
class TestClass2{
private:
int* pX;
public:
explicit TestClass2(int to_x)
{
pX = new int;
*pX = to_x;
}
~TestClass2()
{
delete pX;
std::cerr << "destruction: 2." << std::endl;
}
const int& value() const
{
return *pX;
}
};
DWORD WINAPI thread_func(LPVOID pN)
{
Sleep(200);
TestClass1 test((*((TestClass2*)pN)).value());
test.show();
return 0;
}
int main(int argc, char* argv[])
{
for (int i = 0; i < 3; ++i) {
TestClass2 n(5);
HANDLE hThrd;
DWORD thrdId;
hThrd = CreateThread( NULL,
0,
thread_func,
(LPVOID)&n,
0,
&thrdId);
std::cerr << "loop: " << i+1 << std::endl;
}
Sleep(2000);
std::cout << "main() ok." << std::endl;
return 0;
}
可以看到函数返回了错误的值(至于为什么每次都是36我还不清楚,但是至少不是正确的数字5),这是因为在线程调用TestClass2的对象之前已经被析构的缘故。
loop: 1
destruction: 2.
loop: 2
destruction: 2.
loop: 3
destruction: 2.
36
destruction: 1.
36
destruction: 1.
36
destruction: 1.
main() ok.
请按任意键继续. . .
所以,如果我们设想构造一个类,这个类的对象可以调用包含this的线程,那么这个对象一定不能是局部变量,或者说,我们必须在循环的{}对之前先把这些对象构造出来。这与我们的需求不符合——我们并不知道需要多少对象以及如何构造(比如构造TCP的通讯socket需要accept()接受客户端的信息),在这种情况下,我们只能在线程中去构造对象,这样的对象生命周期跟线程函数一样。
或者说,如果我们希望用类来封装线程,那么这些可以调用线程的对象必须是全局的。相关内容请参考本人前面的教程“初试多线程”等。
posted on 2010-06-05 21:06
lf426 阅读(782)
评论(0) 编辑 收藏 引用 所属分类:
语言基础、数据结构与算法 、
Win32与VC