1、基础知识:
1)进程 (process):是一个具有一定功能的程序在一个数据集合的一次动态执行过程。进程由正文段,用户数据段以及系统数据段共同组成一个执行环境,与处理器、存储器和外设等资源的分配和回收相对应,进程是计算机系统资源的使用主体,也是操作系统分配资源的基本单位。
2)线程:在多个进程并发执行时,进程切换的开销比较大,影响了进程间通信的效率。因此提出了更小的能独立运行的基本单位——线程。线程时进程的一个实体,是cpu调度和分配的基本单位,除了一些在运行中必不可少的资源,线程不拥有系统资源,但是线程可以和同属于一个进程的其他线程共享进程的全部资源。
3)传统的操作系统中,进程是分配资源、独立调度和分配的基本单位,引入线程后,线程当作调度和分配的基本单位,进程仍然是拥有资源的基本单位。
4)关系:为了让进程完成一些工作,进程必须至少占有一个线程,所以线程是描述进程内的执行,正是线程负责执行包含在进程的地址空间的代码。
5)互锁函数: 运行在用户模式,它能保证当一个线程访问一个变量时,其他线程无法访问此变量,以确保变量值的唯一性。这种访问方式叫做原子访问。如InterlockedIncrement(LPLONG)等等。
6)事件对象:事件对象运行在内核模式,利用等待函数来等待所需的事件、信号,在等待的过程中,线程处于睡眠态,当接收到信号后,内核恢复线程的运行。等待函数如:WaitForSingleObject、WaitForMultipleObjects等四个。和事件有关的函数:CreateEvent、SetEvent 、PulseEvent 、ResetEvent 、OpenEvent等。
其中,CreateEvent创建一个事件对象,参数1必须为NULL,参数2指定是否手工重新设置事件对象的状态,如果为FALSE,则当等待函数接到信号并返回后此事件对象被自动置为无效,这时等待此事件对象的其他线程就不会被唤醒;如果为TRUE,则不会被置为无效,其他等待此事件对象的的线程也将被唤醒。
ResetEvent函数可以手工将事件对象置为无效。
SetEvent函数将事件对象置为有效。
OpenEvent打开已经创建的事件对象,一般用于不同进程内的线程同步。
2、线程的编程技术
1)编写线程函数,其必须有如小原型:
DWORD WINAPI MyThread(LPVOID lpvThreadParm);
注意只能有一个参数,这个函数不能由用户调用,由操作系统调用一个内部函数如StartOfThread。
2)创建线程:一个线程的主线程由操作系统自动生成,由主线程创建其他线程用CreateThread函数。
3)终止线程:某线程调用了ExitThread函数,终止自己;调用TerminateThread函数可以终止指定的线程。
4)其他函数:设定优先级SetThreadPriority、挂起线程SuspendThread、恢复线程ResumeThread。
WINAPI
CreateThread (
LPSECURITY_ATTRIBUTES lpsa, // security属性,在WinCE下须为NULL
DWORD cbStack, // 堆栈大小,除非定义宏,否则被忽略
LPTHREAD_START_ROUTINE lpStartAddr, // 起始地址,即C的函数指针
LPVOID lpvThreadParam, // 自定义的传入线程参数
DWORD fdwCreate, // 标识线程是否立即运行,默认是
LPDWORD lpIDThread // 新线程ID
);
线程自身应用return结束,也可使用ExitThread()结束;主线程可以使用WaitForSingleObject(hThreadHandle, dwMilliseconds)等待线程结束,然后使用GetExitCode()获得返回码,最后使用CloseHandle()释放核心对象
AFX_THREADPROC pfnThreadProc, // 线程起始函数
LPVOID pParam, // 自定义参数
int nPriority = THREAD_PRIORITY_NORMAL, // 优先级
UINT nStackSize = 0 , // 栈大小
DWORD dwCreateFlags = 0 , // 标识线程是否立即运行,默认是
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL // 安全属性
);
CWinThread * AFXAPI AfxBeginThread( // 创建UI线程
CRuntimeClass * pThreadClass, // 指定线程类,为CWinThread子类
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0 ,
DWORD dwCreateFlags = 0 ,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);
pSubThread -> SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
if (INVALID_HANDLE_VALUE == hCloseEvent) {... ...}
… …
ResetEvent(hCloseEvent);
DWORD dwEvent = WaitForMultipleObjects( 3 ,signals,FALSE, - 1 );
if (WAIT_OBJECT_0 == dwEvent) {
if (WAIT_OBJECT_0 + 1 == dwEvent) {
BOOL bInitiallyOwn = FALSE, // 标识初始时是否有信号
BOOL bManualReset = FALSE, // 标识是否为手动置位
LPCTSTR lpszNAme = NULL, // 在进程间同步是可以指定名字
LPSECURITY_ATTRIBUTES lpsaAttribute = NULL // 安全标识
);
CSyncObject * ppObjects[], // 同步对象数组
DWORD dwCount, // 同步对象个数
BOOL bInitialLock = FALSE // 标识初始时是否访问对象
);
#define EVNT_CNT 3
class EventLock
{
public:
DWORD WaitForEvents();
void SetEvent(int iNum);
void ResetEvent(int iNum);
EventLock();
virtual ~EventLock();
static CEvent *pevnt[EVNT_CNT]; // EVNT_CNT标识事件对象数
private:
static CEvent evntClose, evntBegin, evntPause;
CMultiLock *pLock;
} ;
// 创建CEvent实例:
CEvent EventLock::evntClose (FALSE,TRUE);
CEvent EventLock::evntBegin (FALSE,TRUE);
CEvent EventLock::evntPause (FALSE);
// 初始化同步对象数组:
CEvent * EventLock::pevnt[] = {&evntClose,&evntBeginSample,
&evntPauseSample, &evntPreSample} ;
// 在构造器中创建CMultiLock实例:
EventLock::EventLock()
{
pLock = new CMultiLock((CSyncObject **)EventLock::pevnt,EVNT_CNT);
}
EventLock:: ~ EventLock()
{
delete pLock;
}
// 与Event相同的MFC CEvent置位、复位操作:
void EventLock::ResetEvent( int iNum )
{
ASSERT(0<=iNum && iNum<EVNT_CNT);
pevnt[iNum]->ResetEvent();
}
void EventLock::SetEvent( int iNum)
{
ASSERT(0<=iNum && iNum<EVNT_CNT);
pevnt[iNum]->SetEvent();
}
// 使用CMultiLock::Lock()等待事件激发,此处为等待任意事件激发:
DWORD EventLock::WaitForEvents()
{
DWORD dwEvent = 0;
dwEvent = pLock->Lock(INFINITE, FALSE); // 第二个参数为TRUE则等待全部事件
dwEvent -= WAIT_OBJECT_0;
return dwEvent;
}