多线程教程之一---线程的创建和参数设置
来源:互联网 发布:mac邮箱离线 编辑:程序博客网 时间:2024/05/04 06:45
1. 线程的创建
在程序中调用CreateThread函数可以创建一个线程:HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);
每个参数的含义为:
LPSECURITY_ATTRIBUTES lpThreadAttributes 一般设为NULL。
该参数是指向一个SECURITY_ATTRIBUTES结构的指针。如果要赋予该线程内核对象缺省的安全属性,可以传递一个NULL。如果希望所有的子进程能够继承该线程对象的句柄,须设定一个SECURITY_ATTRIBUTES结构,它的bInheritHandle成员应初始化为TRUE。
DWORD dwStackSize 一般设为0
该参数指定线程栈的大小。每个线程都拥有它自己的堆栈。如果dwStakSize为0,系统默认保留的栈的空间为1MB。
LPTHREAD_START_ROUTINE lpStartAddress 入口函数
该参数用于指定新建线程的入口函数的地址。可以创建多个线程,使用相同的入口函数地址。该入口函数的原型为:
DWORD WINAPI ThreadFunc(LPVOID lpParameter);
名字可以改变,返回类型和参数相同就可以。
DWORD dwCreationFlags 一般为0
该参数控制创建线程的标志,它可以是0或者CREATE_SUSPENDED。如果是0,则新建立的线程在创建完毕后被系统调度程序调度(可能被执行,也可能不被执行,这取决于系统中其他线程的优先级情况)。如果该值为CREATE_SUSPENDED,系统在创建完新线程后,新线程被系统挂起,直到有其他线程执行了带该新线程句柄的ResumeThread()函数后,新线程才被激活。
LPDWORD lpThreadId 一般为NULL
该参数指定新线程的ID。在Windows95中,该参数不能为NULL,否则会引起错误,在Windows 2000中该参数可以为NULL。
例1:创建线程,并传递参数:
DWORD WINAPI SubThread(LPVOID lpParam){TRACE("SubThread,lpParam is:%d\n",lpParam);return 0;}void MainThread(){HANDLE hThread=CreateThread(NULL,0,SubThread,(LPVOID)123,0,NULL);Sleep(1000);CloseHandle(hThread);}例2:
创建挂起的新线程,老线程执行一些工作后,再激活新创建的线程。
DWORD WINAPI SubThread(LPVOID lpParam){TRACE("SubThread,lpParam is:%d\n",lpParam);return 0;} void MainThread(){HANDLE hThread=CreateThread(NULL,0,SubThread,(LPVOID)123,CREATE_SUSPENDED,NULL);TRACE("SubThread is created\n");ResumeThread(hThread);Sleep(1000);CloseHandle(hThread);}2. 线程的终止
可以使用下面方法来终止线程:
线程函数的返回;
(1)通过调用ExitThread函数,线程将自己撤销;
(2)同一个进程或者另一个进程中的线程调用TerminateThread函数终止另外一个线程的运行;
(3)包含线程的进程终止运行(主线程退出)。
1、 线程函数返回。
这是确保线程的所有资源被正确地清除的唯一办法。当线程函数返回时,如下情况将会发生:在线程函数中创建的所有C++对象将通过它们的析构函数正确地撤销;
操作系统将正确地释放线程的堆栈使用的内存;
系统将线程的退出代码设置为线程函数的返回值;
系统递减线程内核对象的引用计数。
2、 ExitThread函数。
可以通过在线程中调用ExitThread函数,来强制终止自身线程的运行。原型为:VOID ExitThread(DWORD dwExitCode);
该函数将终止自身线程的运行,并导致操作系统清除该线程使用的所有操作系统资源。但是,C++资源(如C++对象)将不被正确地撤销。由于这个原因,最好从线程函数返回,而不是通过调用ExitThread来返回。
3、 TerminateThread函数。调用TerminateThread函数将终止指定线程的运行,原型为:
BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);
//HANDLE hThread—将要终止的线程的句柄
//DWORD dwExitCode—传递给将要终止的线程的退出代码
与ExitThread不同,ExitThread是撤销自身线程,而TerminateThread能够撤销任何线程。
要注意的是,TerminateThread是异步运行的函数,也就是说,它告诉系统要终止指定线程的运行,但是该函数返回后,并不能保证指定的线程已经撤销,如果要确切地知道被指定的线程是否已经被撤销,请调用WaitForSingleObject等函数。4、 进程终止运行(主线程退出)
5、 线程终止运行时,会发生下列操作:
线程拥有的所有USER对象句柄均被释放。在Windows中,线程所创建的大部分对象归它的进程所有。但是,线程也可以拥有两个USER对象:窗口和钩子。当创建这些对象的线程终止运行时,系统会自动释放这些对象。其它对对象只有在进程终止时才被释放;
线程的退出代码从STILL_ACTIVE改为线程函数返回值或者传递给ExitThread或者TerminateThread的代码;
线程内核对象的状态变为通知(信号)状态;
如果线程是进程中最后一个活动线程,进程也被终止;
线程内核对象的使用计数递减1。
例1:
线程的正常退出。注意!在线程中new出来的资源并不能随着线程退出而自动释放!!!
class CTest{private:int m_iId;public:CTest(int iId){m_iId=iId;}virtual ~CTest(){TRACE("ID:%d ~CTest()\n",m_iId);}}; DWORD WINAPI SubThread(LPVOID lpParam){CTest obj(1),*pObj;pObj=new CTest(2); //注意,堆分配的资源并不随着线程的退出而自动释放Sleep(500);return 999;} void MainThread(){DWORD dwRet;HANDLE hThread=CreateThread(NULL,0,SubThread,NULL,0,NULL);GetExitCodeThread(hThread,&dwRet);TRACE("SubThread exitcode:%d\n",dwRet);//很可能为STILL_ACTIVESleep(1000);GetExitCodeThread(hThread,&dwRet);TRACE("SubThread exitcode:%d\n",dwRet);//很可能为999CloseHandle(hThread);}例2:
自身调用ExitThread退出线程
class CTest{private:int m_iId;public:CTest(int iId){m_iId=iId;}virtual ~CTest(){TRACE("ID:%d ~CTest()\n",m_iId);}}; DWORD WINAPI SubThread(LPVOID lpParam){CTest obj(1),*pObj; pObj=new CTest(2); //注意,堆分配的资源并不随着线程的退出而自动释放Sleep(500);ExitThread(1000); //接下来的返回语句将得不到执行,obj也不会被析构return 999; } void MainThread(){DWORD dwRet;HANDLE hThread=CreateThread(NULL,0,SubThread,NULL,0,NULL);GetExitCodeThread(hThread,&dwRet);TRACE("SubThread exitcode:%d\n",dwRet);//很可能为STILL_ACTIVESleep(1000);GetExitCodeThread(hThread,&dwRet);TRACE("SubThread exitcode:%d\n",dwRet);//很可能为1000CloseHandle(hThread);}例3:
调用TerminateThread来终止另外一个线程的运行。
DWORD WINAPI SubThread(LPVOID lpParam){CTest obj(1),*pObj; pObj=new CTest(2); //注意,堆分配的资源并不随着线程的退出而自动释放Sleep(500);return 999; } void MainThread(){DWORD dwRet;HANDLE hThread=CreateThread(NULL,0,SubThread,NULL,0,NULL);GetExitCodeThread(hThread,&dwRet);TRACE("SubThread exitcode:%d\n",dwRet); //很可能为STILL_ACTIVETerminateThread(hThread,1001); //强行终止线程hThread的运行//TerminateThread是异步函数,所以可能此时hThread并没撤销完毕。Sleep(500); GetExitCodeThread(hThread,&dwRet);TRACE("SubThread exitcode:%d\n",dwRet); //很可能为1001CloseHandle(hThread);}3. 线程的暂停(挂起)与恢复运行
任何线程都可以调用SuspendThread()来暂停另一个线程的运行(只要拥有线程的句柄)。原型为:
DWORD SuspendThread(HANDLE hThread);
返回值是前一次暂停计数,一个线程能够被暂停的最多次数是MAXIMUM_SUSPEND_COUNT,
参数HANDLE hThread表示将要被挂起的线程
调用ResumeThread()可以让挂起的线程恢复运行。原型为:
DWORD ResumeThread(HANDLE hThread);
返回值是前一次暂停计数,参数HANDLE hThread表示将要被恢复的线程
例:
#include <windows.h>#include <stdio.h>DWORD WINAPI ThreadProc(LPVOID lpParam){printf("subThread: lpParam is %d\n", lpParam);return 0;}void main(){HANDLE hThread=CreateThread(NULL, 0, ThreadProc, (LPVOID)123, CREATE_SUSPENDED, 0);printf("a new thread is created\n");ResumeThread(hThread);Sleep(1000);CloseHandle(hThread);}
HANDLE g_hThread1=NULL;HANDLE g_hThread2=NULL; void ConsumeCPU(){char szBuf[8192];for(int i=0;i<200000;i++){sprintf(szBuf,"%d",rand());memset(szBuf,0,sizeof(szBuf));}}DWORD WINAPI SubThread(LPVOID lpParam){int iLoop=0;while(TRUE){ConsumeCPU();TRACE("Thread %X loop:%d\n",GetCurrentThreadId(),iLoop++);}return 0;}void CMy0621Dlg::OnOK() {g_hThread1=CreateThread(NULL,0,SubThread,NULL,0,NULL);g_hThread2=CreateThread(NULL,0,SubThread,NULL,0,NULL);SetThreadPriority(g_hThread1,THREAD_PRIORITY_LOWEST);SetThreadPriority(g_hThread2,THREAD_PRIORITY_LOWEST);} void CMy0621Dlg::OnButtonReduce() {SetThreadPriority(g_hThread1,THREAD_PRIORITY_IDLE);} void CMy0621Dlg::OnButtonRestore() {SetThreadPriority(g_hThread1,THREAD_PRIORITY_LOWEST);}
- 多线程教程之一---线程的创建和参数设置
- 【多线程】多线程教程之(一)---线程的创建和参数设置
- Java的线程和多线程教程
- 多线程编程-线程的创建和终止
- 多线程编程-线程的创建和终止
- 多线程编程-线程的创建和终止
- 多线程编程-线程的创建和终止
- 多线程编程-线程的创建和终止
- 多线程编程-线程的创建和终止
- 多线程编程-线程的创建和终止
- 多线程01--线程的创建和启动
- java多线程---线程的创建和运行
- 多线程-线程的创建
- 多线程 线程的创建方式和多线程共享资源
- MFC多线程的创建,包括工作线程和用户界面线程
- MFC多线程的创建,包括工作线程和用户界面线程
- MFC多线程的创建,包括工作线程和用户界面线程
- MFC多线程的创建,包括工作线程和用户界面线程
- 探索推荐引擎内部的秘密:推荐引擎初探
- ORACLE内存命中率
- DATAGUARD详细配置
- Ubuntu 11.04软件及配置
- VBA Excel宏操作示例
- 多线程教程之一---线程的创建和参数设置
- LINUX下面ORACLE RAC的安装
- android获取屏幕尺寸、密度
- Red Hat Sets a New Standard for the Next Generation of Operating Systems
- 写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数
- PHP学习笔记(五)错误和异常处理
- 多线程教程之二---线程间同步
- 使用C++读写Excel
- Eclipse中查看源码