1.问题的提出
希望实现如下功能:一个加法线程实现对全局变量a执行加法操作,另一个减法线程对全局变量a执行减法操作,当a大于30时,退出加法线程,当a小于等于0时,退出减法线程。
2.代码的实现
// CThreadPoolTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#define _AFXDLL
#include <afxwin.h>
//全局操作变量
int a = 10;
//加法线程
CWinThread *addThread = NULL;
//减法线程
CWinThread *minusThread = NULL;
//临界区资源对象
CRITICAL_SECTION cs;
UINT add(LPVOID lParameters)
{
while (true) {
EnterCriticalSection(&cs);
printf("add thread. a = %d\n", a);
a += 2;
if (a >= 30) {
printf("退出线程add \n");
LeaveCriticalSection(&cs); //1
//break;
DWORD dwExitCode = 0;
GetExitCodeThread(addThread->m_hThread, &dwExitCode);
AfxEndThread(dwExitCode, TRUE);
}
LeaveCriticalSection(&cs);
}
return 0;
}
UINT minus(LPVOID lParameters)
{
while (true) {
EnterCriticalSection(&cs);
printf("minus thread. a = %d\n", a);
a -= 1;
if (a <= 0) {
printf("退出线程minus. a = %d\n",a);
LeaveCriticalSection(&cs); //1
//break;
DWORD dwExitCode = 0;
GetExitCodeThread(minusThread->m_hThread, &dwExitCode);
AfxEndThread(dwExitCode, TRUE);
}
LeaveCriticalSection(&cs);
}
return 0;
}
int main()
{
//初始化临界区资源对象
InitializeCriticalSection(&cs);
//创建CWinThread线程
addThread = AfxBeginThread(add,LPVOID(NULL), THREAD_PRIORITY_NORMAL,0,NULL);
minusThread = AfxBeginThread(minus, LPVOID(NULL), THREAD_PRIORITY_NORMAL, 0, NULL);
_gettch();
return 0;
}
3.多线程编程函数
a)线程创建
AfxBeginThread
定义有两种形式:
CWinThread* AfxBeginThread(
AFX_THREADPROC pfnThreadProc,
LPVOID pParam,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);
CWinThread* AfxBeginThread(
CRuntimeClass* pThreadClass,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);
第一个形式是工作者线程,其参数定义如下:
pfnThreadProc | 线程的函数入口,此函数的声明形式一定要是 UINT ThreadFunctioon(LPVOID pParam),不能设置为NULL |
pParam | 传递到线程函数的参数 |
nPriority | 线程的优先级。设置为0,表示和主线程拥有相同的优先级 |
nStackSize | 指定新创建的线程的栈的大小.如果为 0。新创建的线程具有和主线程一样的大小的栈 |
dwCreateFlags | 指定创建线程以后,线程的标志.可以指定两个值:CREATE_SUSPENDED : 线程创建以后,会处于挂起状态,直到调用:ResumeThread;0 : 创建线程后就开始运行. |
lpSecurityAttrs | 指向一个 SECURITY_ATTRIBUTES 的结构体,用它来标志新创建线程的安全性.如果为 NULL,那么新创建的线程就具有和主线程一样的安全性. |
第二个形式是用户界面线程
pThreadClass | 从CWinThread派生的RUNTIME_CLASS类 |
nPriority | 线程的优先级。设置为0,表示和主线程拥有相同的优先级 |
nStackSize | 指定新创建的线程的栈的大小.如果为 0。新创建的线程具有和主线程一样的大小的栈 |
dwCreateFlags | 指定创建线程以后,线程的标志.可以指定两个值:CREATE_SUSPENDED : 线程创建以后,会处于挂起状态,直到调用:ResumeThread;0 : 创建线程后就开始运行. |
lpSecurityAttrs | 指向一个 SECURITY_ATTRIBUTES 的结构体,用它来标志新创建线程的安全性.如果为 NULL,那么新创建的线程就具有和主线程一样的安全性. |
b)线程的退出
一种使用AfxEndThread方式
void AFXAPI AfxEndThread(
UINT nExitCode,
BOOL bDelete = TRUE
);
nExitCode | 线程的退出码 |
bDelete | 是否从内存删除线程对象 |
GetExitCodeThread
BOOL WINAPI GetExitCodeThread(
_In_ HANDLE hThread,
_Out_ LPDWORD lpExitCode
);
hThread | 线程句柄 |
lpExitCode | 保存线程退出状态的变量 |
第二种使用当满足一定条件退出死循环的方式,如下:
//add函数
printf("退出线程add \n");
LeaveCriticalSection(&cs);
break;
//DWORD dwExitCode = 0;
//GetExitCodeThread(addThread->m_hThread, &dwExitCode);
//AfxEndThread(dwExitCode, TRUE);
//minus函数
printf("退出线程minus. a = %d\n",a);
LeaveCriticalSection(&cs);
break;
//DWORD dwExitCode = 0;
//GetExitCodeThread(minusThread->m_hThread, &dwExitCode);
//AfxEndThread(dwExitCode, TRUE);
4.注意
对于使用临界区控制全局变量的时候,要特别注意避免死锁问题的出现。
比如还是上面的那个程序,当把两个线程函数中的if语句块内的
LeaveCriticalSection(&cs);
屏蔽掉后运行,会发现,当退出add或者minus之后,另一个线程无法执行到输出退出信息,就是由于当其他一个线程退出时,未能释放锁导致的。