随笔 - 96  文章 - 255  trackbacks - 0
<2010年6月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

E-mail:zbln426@163.com QQ:85132383 长期寻找对战略游戏感兴趣的合作伙伴。

常用链接

留言簿(21)

随笔分类

随笔档案

SDL相关网站

我的个人网页

我的小游戏

资源下载

搜索

  •  

积分与排名

  • 积分 - 485037
  • 排名 - 37

最新评论

阅读排行榜

评论排行榜

还是先看一段非多线程的程序。我们用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 阅读(766) 评论(0)  编辑 收藏 引用 所属分类: 语言基础、数据结构与算法Win32与VC

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理