多线程的一点思考
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核心编程》中说终止进程的运行的最好方式是主线程的进入点函数返回
,这样能保证所有线程资源能够得到正确清除。
实际上使用下面这个例子:
程序的运行结果如下:
A::A(global)
A::A(thread_func)
A::~A(global)
可见线程thread_func中的local_a析构函数未被调用,仍然可能有资源泄漏。可见,每一个线程函数也都要小心,要确保在主线程结束之前能正常退出,而主线程也要能保证所有其他线程正常退出后再退出。
而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析构函数未被调用,仍然可能有资源泄漏。可见,每一个线程函数也都要小心,要确保在主线程结束之前能正常退出,而主线程也要能保证所有其他线程正常退出后再退出。
相关文章推荐
- 关于java中多线程的问题的一点思考(什么情况下需要考虑到线程,以及线程安全的问题?)
- 对java多线程的一点思考
- 自己对多线程的一点思考
- 关于多线程的一点思考
- 关于多线程编程的一点思考
- 关于main函数参数的一点思考
- 对做技术的一点思考
- 多进程和多线程设计思考
- 关于STM32驱动DS1302实时时钟的一点思考
- epoll的一点思考(1)
- 关于多线程中如何实现生产者消费者和谐统一的思考
- 关于多线程的思考
- 关于交大二手市场的一点思考
- 一点BPXA的思考
- 关于SEH局部展开的一点思考
- 关于多线程的一点感想
- 关于员工离职的一点思考
- 从有上下界有源汇最小流的实践中得出的一点思考
- 二分类——多分类:一点思考
- 谈谈SIFT、PCA-SIFT、SURF及我的一点思考