一、线程
windows应用程序可以由一个进程或多个进程组成,多个进程间通信(套接字、共享内存、命名管道等)来协同工作。而一个进程可以由一个线程或多个线程组成。每个进程都有单线程开始,在单线程里可以建立另外执行线程。
线程可以执行程序代码的任何部分,也包括由其他线程执行的部分。线程是windows操作系统分配CPU时间的基本实体。每个线程都有以一份在保存其上下文数据,为了操作系统调度处理之用。上下文数据包含线程的寄存器、内核堆栈、线程环境块和在线程的进程地址空间中的用户堆栈。进程中所有线程共享虚拟地址空间并能访问全局变量和进程的系统资源。
二、建立线程、挂起线程、恢复线程
CreateThread函数建立进程的一个新线程,建立新线程必须指定新线程执行代码的开始地址。执行代码开始地址也就是在程序代码中定义函数名称。进程可以同时执行同一函数的多个线程,但这些线程是区别的,有不同的线程句柄、不同的线程标识ID,不同函数参数,不同的线程上下文数据。
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadID
);
参数的含义如下:
lpThreadAttrivutes:指向SECURITY_ATTRIBUTES的指针,用于定义新线程的安全属性,一般设置成NULL;
dwStackSize:分配以字节数表示的线程堆栈的大小,默认值是0;
lpStartAddress:指向一个线程函数地址。每个线程都有自己的线程函数,线程函数是线程具体的执行代码;
lpParameter:传递给线程函数的参数;
dwCreationFlags:表示创建线程的运行状态,其中CREATE_SUSPEND表示挂起当前创建的线程,而0表示立即执行当前创建的进程;
lpThreadID:返回新创建的线程的标识ID;
由CreateThread返回的句柄对线程有完全的访问权。
可以调用CloseHandle关闭线程对象。
使用SuspendThread函数,可以挂起线程,在线程挂起是,不会被调度。
使用ResumeThread函数,恢复线程执行。
三、线程同步
要避免冲突,有必要同步多线程对共享资源的访问,同步还可以保证相互依赖代码能正确顺序执行。Win32 API提供一组同步多线程的对象。这些对象包含:
同步对象:临界区(Critical Section)、互斥对象(Mutex)和信号量(Semaphore)
文件句柄
线程句柄
进程句柄
这些对象的状态是两态的,分别是有信号和无信号。当这些对象的句柄在等待函数(WaitForSingleObject MaitForMultipleObjects)调用指定时,调用线程的执行一直阻塞到指定对象的状态为有信号。
- 临界区Critical Section
临界区是一段执行程序代码,在这一段执行程序代码不允许两个或两个以上的线程同时执行。在所有同步对象中,临界区使用最简单,但它只能同步同一进程的所有线程。第一线程调用EnterCriticalSection,所有别的线程都不能该临界区控制的代码块,只有第一线程调用LeaveCriticalSection之后,下一个线程才能唤醒。
1)初始化临界区对象
InitializeCriticalSection(&gCriticalSection);
2) 临界区
EnterCriticalSection(&gCriticalSection);
try
{
}
catch (...)
{
}
LeaveCriticalSection(&gCriticalSection);
3)删除临界区对象
InitializeCriticalSection(&gCriticalSection)
2. 互斥对象
互斥对象既能够在单一应用程序下使两个或更多线程同步,也可以在不同的进程下进行多线程操作。如果一个线程占有了这个互斥对象,这个互斥对象被标记;相反,如果没有线程占有这个互斥对象,那么这个互斥对象就不会被标记,互斥对象是在占有与释放之间进行转换。
1) 创建互斥对象
hMutex = CreateMutex(NULL, FALSE, NULL);
2) 使用互斥对象同步线程,并释放互斥对象
WaitForSingleObject(hMutex, INFINITE);
Try
{
}
catch (...)
{
}
ReleaseMutex(hMutex);//释放互斥对象
3) 关闭互斥对象
CloseHandle(hMutex);
3. 信号量
信号量不一定是锁定某一个资源,信号量有一个与之关联的资源计数,所以
一个信号量允许多个线程同时获取对它的访问许可。
- 创建信号量
m_hInSemaphore=CreateSemaphore(NULL,1, 1,sharename);
计数最大值:1,初始值:1 - 使用信号量同步多个线程
WaitForSingleObject(m_hInSemaphore, INFINITE);//等待信号量>0
Try
{
}
catch (...)
{
}
ReleaseSemaphore(m_hInSemaphore, 1, NULL);//信号量++
3) 关闭信号量
CloseHandle(m_hInSemaphore) ;