实验四 windows 2000中线程的创建和同步控制
一、实验目的
1、加深对线程概念的理解,明确进程和线程的区别
2、掌握windows 2000中线程创建和同步控制的编程方法 二、实验任务
在windows2000的环境下,创建一个控制台进程,此进程创建两个并发线程,一个是读线程,另一个是写线程。这两个线程共享一个数组A,写线程对数组分别进行10次写操作,每次写操作对A的每个元素赋一个相同的值;读线程对数组分别进行10次读操作,每次读操作输出A中所有元素的值。写出相应代码,并分析运行结果。修改代码,使每次读写互斥,即每次对数组的写操作结束后才能进行写操作,反之亦然。 三、实验指导
线程是操作系统分时调度分配 CPU时间的基本实体。一个线程可以执行程序的任意部分的代码,即使这部分代码被另一个线程并发地执行;一个进程的所有线程共享它的虚拟地址空间、全局变量和操作系统资源。之所以有线程这个概念,是因为以线程而不是进程为调度对象效率更高:由于创建新进程必须加载代码,而线程要执行的代码已经被映射到进程的地址空间,所以创建、执行线程的速度比进程更快。一个进程的所有线程共享进程的地址空间和全局变量,所以简化了线程之间的通讯。
1、线程的创建
使用 CreateThread函数创建线程,CreateThread的原型如下: HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
DWORD dwCreationFlags, // creation flags LPDWORD lpThreadId );
其中:
lpThreadAttributes 表示创建线程的安全属性,NT下有用。
dwStackSize 指定线程栈的尺寸,如果为0则与进程主线程栈相同。 lpStartAddress 指定线程开始运行的地址。 lpParameter 表示传递给线程的32位的参数。
dwCreateFlages 表示是否创建后挂起线程(取值CREATE_SUSPEND),挂起后调用ResumeThread继续执行。
lpThreadId 用来存放返回的线程ID。
线程的优先级别
进程的每个优先级类包含了五个线程的优先级水平。在进程的优先级类确定之后,可以改变线程的优先级水平。用 SetPriorityClass设置进程优先级类,用SetThreadPriority设置线程优先级水平。
Normal 级的线程可以被除了Idle级以外的任意线程抢占。
6
《操作系统》实验指导书
2、线程的终止
以下情况终止一个线程:
? 调用了 ExitThread函数; ? 线程函数返回:主线程返回导致 ExitProcess被调用,其他线程返回导致ExitThread
被调用;
? 调用 ExitProcess导致进程的所有线程终止; ? 调用 TerminateThread终止一个线程;
? 调用 TerminateProcess终止一个进程时,导致其所有线程的终止。 3、线程同步
同步可以保证在一个时间内只有一个线程对某个资源(如操作系统资源等共享资源)有控制权。共享资源包括全局变量、公共数据成员或者句柄等。同步还可以使得有关联交互作用的代码按一定的顺序执行。
Win32 提供了一组对象用来实现多线程的同步。 这些对象有两种状态:获得信号 (Signaled)或者没有或则信号(Not signaled)。线程通过Win32 API提供的同步等待函数(Wait functions)来使用同步对象。一个同步对象在同步等待函数调用时被指定,调用同步函数地线程被阻塞(blocked),直到同步对象获得信号。被阻塞的线程不占用CPU时间。
同步对象主要有: Critical_section(临界区),Event(事件),Mutex(互斥对象),Semaphores(信号量)。 下面,解释怎么使用这些同步对象。 ? 临界区对象:
首先,定义一个临界区对象 cs: CRITICAL_SECTION cs;
然后,初始化该对象。初始化时把对象设置为 NOT_SINGALED,表示允许线程使用资源:
InitializeCriticalSection(&cs);
如果一段程序代码需要对某个资源进行同步保护,则这是一段临界区代码。在进入该临界区代码前调用 EnterCriticalSection函数,这样,其他线程都不能执行该段代码,若它们试图执行就会被阻塞。完成临界区的执行之后,调用 LeaveCriticalSection函数,其他的线程就可以继续执行该段代码。如果该函数不被调用,则其他线程将无限期的等待。 ? 事件对象
首先,调用 CreateEvent函数创建一个事件对象,该函数返回一个事件句柄。然后,可以设置(SetEvent)或者复位(ResetEvent)一个事件对象,也可以发一个事件脉冲(PlusEvent),即设置一个事件对象,然后复位它。复位有两种形式:自动复位和人工复位。在创建事件对象时指定复位形式。
自动复位:当对象获得信号后,就释放下一个可用线程(优先级别最高的线程;如果优先级别相同,则等待队列中的第一个线程被释放)。
人工复位:当对象获得信号后,就释放所有可利用线程。 最后,使用 CloseHandle销毁创建的事件对象。 ? 互斥对象 首先,调用 CreateMutex创建互斥对象;然后,调用等待函数,可以的话利用关键资源;最后,调用RealseMutex释放互斥对象。
互斥对象可以在进程间使用,但临界区对象只能用于同一进程的线程之间。 ? 信号量对象
在 Win32中,信号量的数值变为0时给以信号。在有多个资源需要管理时可以使用信
7
号量对象。
首先,调用 CreateSemaphore创建一个信号量;然后,调用等待函数,如果允许的话,则利用关键资源;最后,调用RealeaseSemaphore释放信号量对象。 此外,还有其他句柄可以用来同步线程: ? 文件句柄(FILE HANDLES)
? 命名管道句柄(NAMED PIPE HANDELS)
? 控制台输入缓冲区句柄(CONSOLE INPUT BUFFER HANDLES) ? 通讯设备句柄(COMMUNICTION DEVICE HANDLES) ? 进程句柄(PROCESS HANDLES) ? 线程句柄(THREAD HANDLES)
例如,当一个进程或线程结束时,进程或线程句柄获得信号,等待该进程或者线程结束的线程被释放。 等待函数:
Win32 提供了一组等待函数用来让一个线程阻塞自己的执行。等待函数常用的是: ? 等待单个对象的 (FOR SINGLE OBJECT): WaitForSingleObject
函数参数包括同步对象的句柄和等待时间等。 在以下情况下等待函数返回: 同步对象获得信号时返回;
等待时间达到了返回:如果等待时间不限制 (Infinite),则只有同步对象获得信号才返回;如果等待时间为0,则在测试了同步对象的状态之后马上返回。 ? 等待多个对象的 (FOR MULTIPLE OBJECTS) WaitForMultipleObjects
函数参数包括同步对象的句柄,等待时间,是等待一个还是多个同步对象等等。 在以下情况下等待函数返回:
一个或全部同步对象获得信号时返回(在参数中指定是等待一个或多个同步对象); 等待时间达到了返回:如果等待时间不限制 (Infinite),则只有同步对象获得信号才返回;如果等待时间为0,则在测试了同步对象的状态之后马上返回。 4、程序实例
下列程序创建了5个线程,每个线程分别打印一行数字。对该程序运行多次,查看运行结果是否有不同。
#define WIN32_LEAN_AND_MEAN #include
DWORD WINAPI ThreadFunc(LPVOID);
int main() {
HANDLE hThrd; DWORD threadId; int i;
8
《操作系统》实验指导书
for (i=0; i<5; i++) {
hThrd = CreateThread(NULL, 0,
ThreadFunc, (LPVOID)i, 0,
&threadId ); if (hThrd) {
printf(\ CloseHandle(hThrd); } }
// Wait for the threads to complete. Sleep(2000);
return EXIT_SUCCESS; }
DWORD WINAPI ThreadFunc(LPVOID n) {
int i;
for (i=0;i<10;i++) printf(\ return 0; }
实验五 动态分区分配算法的模拟
一、实验目的
1、加深操作系统内存管理过程的理解 2、掌握内存分配算法的基本应用 二、实验任务
请同学们用C/C++实现一个完整的(可变)动态分区管理器,包括分配,回收,分区碎片整理等。希望同学们实现如下功能:
? 初始化功能:内存状态设置为初始状态。
? 分配功能:要求至少使用两种算法,用户可以选择使用。 ? 回收功能:
? 空闲块的合并:即紧凑功能,用以消除碎片。当做碎片整理时,需要跟踪分配的空间,
修改其引用以保证引用的正确性。
? 显示当前内存的使用状态,可以使用表格或图形。 三、实验指导
9
1.基本思想
动态分区是指系统不预先划分固定分区,而是在装入程序的时候划分内存区域,使得为程序分配的分区大小恰好等于该程序的需求量,且分区的个数是动态的。显然动态分区有较大的灵活性,较之固定分区能获得好的内存利用率。
2.数据结构
动态分区管理可以用两种数据结构实现,一种是已分配区表和空闲区表,也就是用预先定义好的系统空间来存放空间分配信息。 另一种也是最常用的就是空闲链表,由于对分区的操作是动态的,所以很难估计数据结构所占用的空间,而且空闲区表会占用宝贵的系统空间,所以提出了空闲链表的概念。其特点是用于管理分区的信息动态生成并和该分区在物理地址上相邻。这样由于可以简单用两个空闲块之间的距离定位已分配空间,不仅节约了系统空间,而且不必维持已分配空间的信息。 本实验是要做一个模拟程序,来模拟动态分区算法的分配和回收过程,并不是真正的去分配和回收内存。基本的模拟方法有两种:
1、先从内存中申请一块存储区,对这块存储区进行模拟的分配和回收活动。
2、不申请存储区,自己定义一块虚拟的存储区,对这块存储区进行模拟的分配和回收活动,分配和回收仅仅是对数据结构的修改而已。
实验六 Linux系统的深入使用
一、实验目的
掌握Linux下进程和作业的控制 掌握Linux下内存管理、文件管理 掌握Linux下用户管理、RPM包管 二、实验任务
练习使用进程和作业的控制命令 练习使用内存管理、文件管理命令 练习使用用户管理、RPM包管命令 三、实验指导
参考《Linux上机实践教程》第四、八、九章内容。
10