createthread函数(createthread函数传递参数)

http://www.itjxue.com  2023-02-23 01:06  来源:未知  点击次数: 

CreateThread()函数每个参数都是什么意思,线程问题帮我都解释一下好么!

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpsa,

DWORD cbStack,

LPTHREAD_START_ROUTINE lpStartAddr,

LPVOID lpvThreadParam,

DWORD fdwCreate,

LPDWORD lpIDThread

);

lpsa:线程句柄的安全属性,比如子进程是否可以继承这个线程句柄,一般情况设置为NULL

cbStack:线程栈大小,一般取0表示默认大小

lpStartAddr:线程入口函数 typedef DWORD (__stdcall *LPTHREAD_START_ROUTINE) (

void* lpThreadParameter );在win32程序中默认的调用函数约定就是WINAPI ,__stdcall = WINAPI 。因此你可以声明你的入口函数为:

DWORD WINAPI ThreadProc( void* lpParamete) {//线程中你要做的事情}

lpvThreadParam:就是线程入口函数的参数,就是ThreadProc( void* lpParamete) 的参数

fdwCreate:控制线程创建的标志一般为0,表示线程立即启动。如果你想创建之后把线程挂起来可以传入CREATE_SUSPENDED ,传入这个参数你需要再适当的地方调用ResumeThread 启动线程

lpIDThread:是线程ID返回值,这个用来接收线程返回的ID

写了这么多我还是怕你不懂:

我举个例子吧,我不保证能运行成功,我也没去编译

DWORD WINAPI ThreadProc( void* lpParameter)

{

int *x = (int*)lpParameter;//获得参数的地址

MessageBox(NULL,TEXT("adf"),NULL,MB_OK);

}

DWORD dwThreadID;

int x = 0;

HANDLE hThread = CreateThread(0,0,ThreadProc,(void*)x,0,dwThreadID);

CloseHandle(hThread);

想学习好windows编程MSDN是必须了解的,你居然不知道什么是MSDN,MSDN就是帮助文档,你可以到百度搜一下并把它下载过来,这对你MFC、Windows API、C/C++等很有帮助的

如何避免使用CreateThread函数导致的内存泄露

CreateThread导致内存泄露的原因

这得从C运行时库说起了。

VC运行时库,有一个宏errno,用来获得上一步操作的错误码,类似于Win32中的GetLastError()函数。在多线程环境下,不同线程调用errno返回的都是caller线程的错误码,绝对不会混淆,这是因为使用了TLS技术。

TLS,Thread Local Storage,是用来存取线程相关数据的一种技术,在Win32中由操作系统的Tls*系列函数提供支持。例如,可以在程序开始的地方调用TlsAlloc()函数,获得一个TLS index,这个index在进程范围内有效,然后可以创建n个线程,在每个线程中使用TlsSetValue(index,data)将线程相关数据和index关联起来,使用TlsGetValue(index)来获取当前线程和index相关联的的线程相关数据。

查看msdn可以发现,Tls*函数的定义如下:

[cpp] view plaincopy

DWORD WINAPI TlsAlloc(void);

BOOL WINAPI TlsSetValue(

__in DWORD dwTlsIndex,

__in LPVOID lpTlsValue

);

LPVOID WINAPI TlsGetValue(

__in DWORD dwTlsIndex

);

BOOL WINAPI TlsFree(

__in DWORD dwTlsIndex

);

观察TlsSetValue/TlsGetValue的原型可以发现,与index关联的数据只能是void *类型,因此通常的做法是在线程开始的时候,为这个线程分配一块内存,用于存储所有与线程相关的数据,然后把这块内存的起始地址与index关联起来。如果这块内存在线程退出的时候没有释放掉,那就有内存泄露的危险。

回到errno,来看看C运行时库是如何实现errno的。

errno的声明和实现如下:

[c-sharp] view plaincopy

/* error.h - errno的声明 */

_CRTIMP extern int * __cdecl _errno(void);

#define errno (*_errno())

/* dosmap.c - errno的实现 */

int * __cdecl _errno(

void

)

{

_ptiddata ptd = _getptd_noexit();

if (!ptd) {

return ErrnoNoMem;

} else {

return ( ptd-_terrno );

}

}

观察_errno的代码,函数首先调用了_getptd_noexit()函数,这个函数的代码如下:

[cpp] view plaincopy

/* tiddata.c - _getptd_noexit()实现 */

_ptiddata __cdecl _getptd_noexit (

void

)

{

_ptiddata ptd;

DWORD TL_LastError;

TL_LastError = GetLastError();

#ifdef _M_IX86

/*

* Initialize FlsGetValue function pointer in TLS by calling __set_flsgetvalue()

*/

if ( (ptd = (__set_flsgetvalue())(__flsindex)) == NULL ) {

#else /* _M_IX86 */

if ( (ptd = FLS_GETVALUE(__flsindex)) == NULL ) {

#endif /* _M_IX86 */

/*

* no per-thread data structure for this thread. try to create

* one.

*/

#ifdef _DEBUG

extern void * __cdecl _calloc_dbg_impl(size_t, size_t, int, const char *, int, int *);

if ((ptd = _calloc_dbg_impl(1, sizeof(struct _tiddata), _CRT_BLOCK, __FILE__, __LINE__, NULL)) != NULL) {

#else /* _DEBUG */

if ((ptd = _calloc_crt(1, sizeof(struct _tiddata))) != NULL) {

#endif /* _DEBUG */

if (FLS_SETVALUE(__flsindex, (LPVOID)ptd) ) {

/*

* Initialize of per-thread data

*/

_initptd(ptd,NULL);

ptd-_tid = GetCurrentThreadId();

ptd-_thandle = (uintptr_t)(-1);

}

else {

/*

* Return NULL to indicate failure

*/

_free_crt(ptd);

ptd = NULL;

}

}

}

SetLastError(TL_LastError);

return(ptd);

}

_getptd_noexit()函数首先通过TLS查找线程相关数据,如果没有找到,就分配一块内存,存放_tiddata结构,并将这块内存与__flsindex相关联。由此可见,errno的确使用了TLS技术,而且通过查找_getptd_noexit() 可以发现,VC运行时库中很多很多函数都使用了TLS,errno只不过是其中的一个典型。

如何在VC中利用系统函数创建一个新的线程

CreateThread函数可以用来创建一个线程,在MSDN中查找这个函数得到如下信息:"The CreateThread function creates a thread to execute within the address space of the calling process."和"If the function succeeds, the return value is a handle to the new thread."所以我们得定义一个句柄用来存放它的返回值。还定义一个指向线程ID的DWORD值dwThreadId。然后我们就可以用CreateThread函数来创建我们的线程了,CreateThread函数有六个参数分别是

LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to security attributes

DWORD dwStackSize, // initial thread stack size

LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function

LPVOID lpParameter, // argument for new thread

DWORD dwCreationFlags, // creation flags

LPDWORD lpThreadId // pointer to receive thread ID

其中第一个参数我们设置为NULL,使这个句柄不能被继承;第二个参数设置为0,使用默认的堆栈大小;第三个参数为线程函数的起始地址,也就是线程函数的函数名;第四个参数为NULL,没有值要传递给线程函数;第五个参数为0,创建好之后马上让线程运行;第六个参数设置为指向线程ID的地址。创建好线程之后,线程函数进行初始化之类的操作,主函数继续执行,此时可以输出被创建线程的ID。我们在主函数中用WaitForSingleObject函数来等待线程函数变成受信(signaled)状态,它的两个参数分别是

HANDLE hHandle, // handle to object to wait for

DWORD dwMilliseconds // time-out interval in milliseconds

第一参数为线程函数的句柄,第二个参数设置为INFINITE,等待线程一直执行完。在程序的最后还要记得用CloseHandle函数关闭线程,这样主函数就写完了。

在线程函数里面我们可以简单地做一些工作,比如设置一个循环,让它输出一定的信息等。源程序如下:

#include windows.h

#include iostream.h

DWORD WINAPI ThreadFunc(HANDLE Thread)

{

int i;

for(i=0;i10;i++)

{

cout"A new thread has created!"endl;

}

return 0;

}

int main(int argc,char* argv[])

{

HANDLE Thread;

DWORD dwThreadId;

Thread=::CreateThread

(NULL,0,ThreadFunc,NULL,0,dwThreadId);

cout"The new thread ID is :"dwThreadIdendl;

::WaitForSingleObject(Thread,INFINITE);

::CloseHandle(Thread);

return 0;

}

在Window xp sp2VC++ 6.0环境下编译通过。

(责任编辑:IT教学网)

更多