您的位置:首页 > 其它

多线程的一点思考

2009-05-27 15:25 197 查看
1.使用CreateThread创建线程,其中第三个参数是LPTHREAD_START_ROUTINE lpStartAddress,

而LPTHREAD_START_ROUTINE被定义为

typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(

LPVOID lpThreadParameter

);

#define WINAPI __stdcall

也就是线程入口函数应该是__stdcall方式。

为什么?(我的想法,不一定正确)

因为线程入口函数和一般的函数调用不一样,在这里调用者(创建新线程的函数)并不知道被调用者(新线程入口函数)什么时候返回,

调用者也就没法在被调用者调用结束后清理参数栈,所以必须有被调用者自己在退出时清理参数栈。

所以为__stdcall方式。

2. 编写C/C++程序,创建线程应使用_beginthread函数。

而_beginthread函数的第一个参数是void (__cdecl * _StartAddress) (void *),需要__cdecl方式的函数。

这是怎么回事?

(1) 其实_beginthread内部调用了CreateThread,它是这样调用的:

ptd->_initaddr = (void *) initialcode;

ptd->_initarg = argument;

CreateThread( NULL,

stacksize,

_threadstart,

(LPVOID)ptd,

CREATE_SUSPENDED,

(LPDWORD)&(ptd->_tid) ))

也就是说,他创建的线程入口函数是_threadstart,而_threadstart原型:

static unsigned long WINAPI _threadstart(void *); 也就是__stdcall方式。

(2)_threadstart内部再调用_callthreadstart,_callthreadstart原型:

static void _callthreadstart(void);

(3)最后由_callthreadstart调用我们的线程函数

__try

{

( (void(__CLRCALL_OR_CDECL *)(void *))(((_ptiddata)ptd)->_initaddr) )

( ((_ptiddata)ptd)->_initarg );

_endthread();

}

在线程结束后,它会调用_endthread,清理C/C++运行期资源。

3.在《Windows核心编程》中说终止进程的运行的最好方式是主线程的进入点函数返回
,这样能保证所有线程资源能够得到正确清除。

实际上使用下面这个例子:

class A
{
public:
A(const string &msg) : _msg(msg)
{
printf("A::A(%s)/n", _msg.c_str());
}
~A()
{
printf("A::~A(%s)/n", _msg.c_str());
}
private:
string _msg;
};
A g_a("global");
DWORD WINAPI thread_func(LPVOID lpThreadParameter)
{
A local_a("thread_func");
while(true)
{
}
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hThread = CreateThread (NULL, NULL, thread_func, NULL, NULL, NULL);
CloseHandle (hThread);
Sleep (1000);
return 0;
}


程序的运行结果如下:

A::A(global)

A::A(thread_func)

A::~A(global)

可见线程thread_func中的local_a析构函数未被调用,仍然可能有资源泄漏。可见,每一个线程函数也都要小心,要确保在主线程结束之前能正常退出,而主线程也要能保证所有其他线程正常退出后再退出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: