线程
1) 定义。
n 线程由两个部分组成:
1、线程的内核对象,操作系统用它来对线程实施管理。内核对象也是系统用来存放线程统计信息的地方。
2、线程堆栈,它用于维护线程在执行代码时需要的所有参数和局部变量。
n 当创建线程时,系统创建一个线程内核对象。该线程内核对象不是线程本身,而是操作系统用来管理线程的较小的数据结构。可以将线程内核对象视为由关于线程的统计信息组成的一个小型数据结构。
n 线程总是在某个进程环境中创建。系统从进程的地址空间中分配内存,供线程的堆栈使用。新线程运行的进程环境与创建线程的环境相同。因此,新线程可以访问进程的内核对象的所有句柄、进程中的所有内存和在这个相同的进程中的所有其他线程的堆栈。这使得单个进程中的多个线程确实能够非常容易地互相通信。
n 线程只有一个内核对象和一个堆栈,保留的记录很少,因此所需要的内存也很少。
n 因为线程需要的开销比进程少,因此在编程中经常采用多线程来解决编程问题,而尽量避免创建新的进程。
2) 运行机制。
n 操作系统为每一个运行线程安排一定的CPU时间 —— 时间片。系统通过一种循环的方式为线程提供时间片,线程在自己的时间内运行,因时间片相当短,因此,给用户的感觉,就好像线程是同时运行的一样。
n 如果计算机拥有多个CPU,线程就能真正意义上同时运行了。
注意的问题:进程是线程的容器,它的周期依赖于主线程的周期。所有的线程周期都依赖于主线程。CloseHandle().作用:关闭内核对象的一次引用,当引用次数为0时,系统将释放该内核对象占用的资源。
3) 互斥现象的产生:当访问公共资源时,还没有来得急作出改变资源内容时,该线程的时间片已经用完了,转到另一个线程时,又要对该作出资源访问、更改,当再一次轮到先前的线程时,公共资源已经被改变了,先前判断的状态已不再为真了,这样导致该线程代码执行混乱。
4) 线程间的同步的方法:
1. 互斥对象(mutex)
n 互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。
n 互斥对象包含一个使用数量,一个线程ID和一个计数器。
n ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。
n 典型代码:
n HANDLE hMutex;//定义全局变量。
n hMutex=CreateMutex(NULL,TRUE,"tickets")//创建MUTEX
n WaitForSingleObject(hMutex,INFINITE);//保护代码
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket : "<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);
5) 事件对象(event)
n 事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。
n 有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
n 典型代码:
HANDLE g_hEvent;//定义全局变量。
g_hEvent=CreateEvent(NULL,FALSE,FALSE,"tickets")//创建Event
WaitForSingleObject(g_hEvent,INFINITE);//保护代码
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket : "<<tickets--<<endl;
}
else
break;
SetEvent(g_hEvent);
6) 关键代码段(CriticalSection)
n 关键代码段(临界区)工作在用户方式下。
n 关键代码段(临界区,对一种公共资源的访问区域)是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权。
n 哲学家进餐的问题本质:线程1拥有了临界区对象A,等待临界区对象B的拥有权,线程2拥有了临界区对象B,等待临界区对象A的拥有权,就造成了死锁。
n 典型代码:
while(TRUE)
{
EnterCriticalSection(&g_csA);
if(tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket : "<<tickets--<<endl;
}
else
break;
LeaveCriticalSection(&g_csA);
}
386



被折叠的 条评论
为什么被折叠?



