《操作系统实验指导书修订版5.doc》由会员分享,可在线阅读,更多相关《操作系统实验指导书修订版5.doc(162页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、目录实验一 Windows任务管理器的使用课外3实验二 进程创立与撤消7实验三 进程间通信12进程间通信之管道133.1管道143.2 其它IPC机制18实验四 创立线程20三、实验内容31实验五 线程同步32实验六 作业调度试验35实验七 死锁实验41一、实验目的41二、实验分析41三、实验设计41四、算法说明41五、程序使用说明41六、死锁实验源程序41实验八 存储管理46实验九 动态分区存储管理方式的主存分配回收50一、实验目的50二、实验主要内容50三、实验原理50四、实验方法与步骤50五、练习题54实验十 页式存储管理实验报告55实验十一 页面置换算法实验70实验十二 设备管理对光驱
2、的翻开、关闭实验;USB的启用和禁用实验,关机、重启实验87mciSendString87OSVERSIONINFO88GetVersionEx90实验十三 设备管理之设备的分配与回收96实验十四 磁盘存储空间的分配与回收102一、实习内容102二、实习目的102三、实习要求102第1题 连续的磁盘存储空间的分配和回收102第2题 用位示图管理磁盘存储空间103第3题 模拟UNIX系统的空闲块成组链接法,实现磁盘存储空间的管理104实验十五 磁盘调度算法109一、实验内容109二、开发环境109三、实验原理.109四、程序结构110实验十五 文件根本操作实验创立、删除等122实验十六 文件管理
3、之目录管理158一、实验目的158二、实验条件158三、实验要求158四、提交实验报告159实验一 Windows任务管理器的使用课外一、实验目的通过在Windows 任务管理器中对程序进程进行响应的管理操作,熟悉操作系统进程管理的概念,学习观察操作系统运行的动态性能.二、实验内容启动并进入Windows环境,单击Ctrl + Alt + Del键,或者右键单击任务栏,在快捷菜单中单击“任务管理器命令,翻开“任务管理器窗口.1. 分别查看每个选项卡的内容,了解相关参数的含义及其当前内容.2. 在“进程选项卡上单击“查看菜单,然后单击“选择列命令.单击要增加显示为列标题的工程,然后单击“确定.分
4、别了解“进程选项卡各列的含义及其当前内容.3. 为更改正在运行的程序的优先级,可在“进程选项卡上右键单击您要更改的程序,指向“设置优先级,然后单击所需的选项.更改良程的优先级可以使其运行更快或更慢 (取决于是提升还是降低了优先级) ,但也可能对其他进程的性能有相反的影响. 查看进程管理器,说明按照名字序号前5个进程的主要用途和功能.4、 修改windows效劳选项,将windows的远程用户修改注册表的效劳设置成禁止. :翻开控制面板 管理工具 效劳 找到Remote Registry,双击,启动类型设置为禁用. 5、 修改windows的磁盘管理并设定配额选项。设定配额的磁盘格式必须是NTF
5、S,如果你的硬盘是FAT32格式;可通过以下命令:convert 盘符:/fs:ntfs 将某一磁盘分区转为NTFS。 6、 修改windows启动选项,将其中的前三个自动启动的选项去掉. :开始 运行 输入msconfig,到启动页.7、 修改windows的虚拟内存交换空间. 8、 修改windows使得windows启动时,显示操作系统列表时间为5秒,并写出启动文件的具体内容. :右键我的电脑 属性 高级 启动和故障恢复的设置 显示列表时间 设为5, 点击编辑 列出具体内容,一般是: boot loadertimeout=0default=multi(0)disk(0)rdisk(0)p
6、artition(1)WINDOWSoperating systemsmulti(0)disk(0)rdisk(0)partition(1)WINDOWS=Microsoft Windows XP Professional /noexecute=optin /fastdetect9、 查看windows本地平安策略,并修改为定期强制修改密码.写出本地平安策略的审核的内容. :开始 运行 输入gpedit.msc 计算机设置 Windows设置 平安设置 账户策略 密码策略 密码最长存留期设置为需要的天数即可. 10、 获得此计算机网卡的网络配置及mac地址. 开始 运行 输入cmd回车 输入i
7、pconfig /all回车即是. 11、 在D盘新建一个文件夹,以自己的拼音缩写命名,并利用命令将其映射为I盘,例如为aaa,命令:subst I: d:aaa.即将c:aaa映射为I盘. 注:I盘是虚拟盘,不是实际的硬盘语法subst drive1:drive2:Path subst drive1:/d参数drive1: 指定要为其指派路径的虚拟驱动器. drive2: 指定包含指定路径的物理驱动器如果不是当前的驱动器. Path 指定要指派给虚拟驱动器的路径. /d 删除虚拟驱动器. /? 在命令提示符显示帮助. 注释以下命令在 subst 命令中使用的驱动器上无法工作或不应使用: ch
8、kdsk Diskcomp Diskcopy format label recover drive1 参数必须在 lastdrive 命令指定的范围之内.如果没有,subst 将显示以下错误消息: Invalid parameter - drive1: 范例假设要为路径 B:UserBettyForms 创立虚拟驱动器 Z,请键入: subst z:b:userbettyforms 现在,不用键入完整路径,而是通过键入虚拟驱动器号,后跟冒号,即可到达该目录,如下所示: z: winxp中的映射盘符命令:subst 另附上软件extrasubst.zip创立虚拟驱动器 12、通过设备管理器查看系
9、统所有组件配置.包括驱动程序,装载的所有程序,windows组件,硬件组件的IRQ等. 13、 查看windows的版本及注册信息. :开始 运行 输入winver回车 14、 利用windows自带的聊天工具,进行局域网内的聊天,并写出详细步骤. 首先启动效劳中的Messager效劳,Sp2以后版本默认为禁止的,将其设为自动, 然后要发消息就开始 运行 输入net send 对方IP地址 信息内容.回车即可 15、 利用命令查看windows进程中每个进程所提供的效劳. 命令:tasklist /SVC 注:查看svchost进程情况 实验二 进程创立与撤消一、实验目的1. 通过创立进程、观
10、察正在运行的进程和终止进程的程序设计和调试操作,进一步熟悉操作系统的进程概念,理解Windows 2000进程生存过程.2. 通过阅读和分析实验程序,学习创立进程、观察进程和终止进程的程序设计方法.二、背景知识1. 创立进程:CreateProcess() 调用的核心参数是可执行文件运行时的文件名及其命令行.下表详细地列出了每个参数的类型和名称.参数名称使用目的LPCTSTR lpApplivationName全部或局部地指明包括可执行代码的EXE文件的文件名LPCTSTR lpCommandLine向可执行文件发送的参数LPSECURIITY_ATTRIBUTES lpProcessAttr
11、ibutes返回进程句柄的平安属性.主要指明这一句柄是否应该由其他子进程所继承LPSECURIITY_ATTRIBUTES lpThreadAttributes返回进程的主线程的句柄的平安属性BOOL bInheritHandle一种标志,告诉系统允许新进程继承创立者进程的句柄DWORD dwCreationFlage特殊的创立标志 (如CREATE_SUSPENDED) 的位标记LPVOID lpEnvironment向新进程发送的一套环境变量;如为null值那么发送调用者环境LPCTSTR lpCurrentDirectory新进程的启动目录STARTUPINFO lpStartupInf
12、oSTARTUPINFO结构,包括新进程的输入和输出配置的详情LPPROCESS_INFORMATION lpProcessInformation调用的结果块;发送新应用程序的进程和主线程的句柄和ID可以指定第一个参数,即应用程序的名称,其中包括相对于当前进程的当前目录的全路径或者利用搜索方法找到的路径;lpCommandLine参数允许调用者向新应用程序发送数据;接下来的三个参数与进程和它的主线程以及返回的指向该对象的句柄的平安性有关.然后是标志参数,用以在dwCreationFlags参数中指明系统应该给予新进程什么行为.经常使用的标志是CREATE_SUSPNDED,告诉主线程立刻暂停.
13、当准备好时,应该使用ResumeThread() API来启动进程.另一个常用的标志是CREATE_NEW_CONSOLE,告诉新进程启动自己的控制台窗口,而不是利用父窗口.这一参数还允许设置进程的优先级,用以向系统指明,相对于系统中所有其他的活动进程来说,给此进程多少CPU时间.接着是CreateProcess() 函数调用所需要的三个通常使用缺省值的参数.第一个参数是lpEnvironment参数,指明为新进程提供的环境;第二个参数是lpCurrentDirectory,可用于向主创进程发送与缺省目录不同的新进程使用的特殊的当前目录;第三个参数是STARTUPINFO数据结构所必需的,用于
14、在必要时指明新应用程序的主窗口的外观.CreateProcess() 的最后一个参数是用于新进程对象及其主线程的句柄和ID的返回值缓冲区.以PROCESS_INFORMATION结构中返回的句柄调用CloseHandle() API函数是重要的,因为如果不将这些句柄关闭的话,有可能危及主创进程终止之前的任何未释放的资源.2. 终止进程:所有进程都是以调用ExitProcess() 或者TerminateProcess() 函数结束的.但最好使用前者而不要使用后者,因为进程是在完成了它的所有的关闭“职责之后以正常的终止方式来调用前者的.而外部进程通常调用后者即突然终止进程的进行,由于关闭时的途径
15、不太正常,有可能引起错误的行为.TerminateProcess() API函数只要翻开带有PROCESS_TERMINATE访问权的进程对象,就可以终止进程,并向系统返回指定的代码.这是一种“野蛮的终止进程的方式,但是有时却是需要的.如果开发人员确实有时机来设计“谋杀(终止别的进程的进程) 和“受害进程 (被终止的进程) 时,应该创立一个进程间通讯的内核对象如一个互斥程序这样一来,“受害进程只在等待或周期性地测试它是否应该终止.三、实验内容1编译运行工程create and terminate ProcessCreateandterminateProcess.dsw,观察运行结果,并阅读和分
16、析实验程序.*主要分析A. void CCreateandterminateProcessDlg:OnCreateprocess()/ TODO: Add your control notification handler code herePROCESS_INFORMATION pi;STARTUPINFO si;/初始化变量memset(&si,0,sizeof(si);si.cb=sizeof(si);si.wShowWindow=SW_SHOW;si.dwFlags=STARTF_USESHOWWINDOW;/翻开记事本程序BOOL fRet=CreateProcess(NULL,c:
17、windowsnotepad.exe c:autoexec.bat,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi);if(!fRet)/创立失败,显示错误信息LPVOID lpMsgBuf;FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SU
18、BLANG_DEFAULT), / Default language(LPTSTR) &lpMsgBuf,0,NULL );AfxMessageBox( (LPCTSTR)lpMsgBuf);LocalFree( lpMsgBuf );elseAfxMessageBox(CreateProcess成功);m_hPro=pi.hProcess;B. void CCreateandterminateProcessDlg:OnTerminateprocess()/判断进程句柄是否合法if(m_hPro)/根据句柄,终止刚刚翻开的记事本程序if(!TerminateProcess(m_hPro,0)/
19、终止出现错误,显示错误信息LPVOID lpMsgBuf;FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), / Default language(LPTSTR) &lpMsgBuf,0,NULL );AfxMessageBox( (LPCTSTR)lpMsgBuf);LocalFree( lpMsgBuf );
20、elseAfxMessageBox(TerminateProcess成功);m_hPro=NULL;elseAfxMessageBox(m_hPro为空);C. 在cpp文件中添加“ #include winbase.hD. 在头文件中添加“protected:HANDLE m_hPro;2编译运行工程Lab2.2proclist.dsw,观察运行结果,并阅读和分析实验程序. *主要分析A 、void CCntrlOtherPrcssDlg:OnStart();B、 void CCntrlOtherPrcssDlg:OnStop(); 3. 编写程序将系统中所有的Notepad进程全部终止.T
21、erminateProcess就可以: BOOL TerminateProcess( HANDLE hProcess, / handle to the process UINT uExitCode / exit code for the process ); 实验三 进程间通信一、实验目的在本实验中,通过对文件映射对象的了解,来加深对Windows 2000线程同步的理解.回忆系统进程、线程的有关概念,加深对Windows 2000线程间通讯的理解;了解文件映射对象;通过分析实验程序,了解线程如何通过文件映射对象发送数据;了解在进程中如何使用文件映射对象.二、背景知识1共享内存:Windows
22、 2000提供了一种在文件中处理数据的方法,名为内存映射文件,也称为文件映射.文件映射对象是在虚拟内存中分配的永久或临时文件对象区域 (如果可能的话,可大到整个文件) ,可将其看作是二进制的数据块.使用这类对象,可获得直接在内存中访问文件内容的能力.文件映射对象提供了强大的扫描文件中数据的能力,而不必移动文件指针.对于多线程的读写操作来说,这一点特别有用,因为每个线程都可能想要把读取指针移动到不同的位置去为了防止这种情况,就需要使用某种线程同步机制保护文件.在CreateFileMapping() API中,一个新的文件映射对象需要有一个永久的文件对象 (由CreateFile() 所创立)
23、.该函数使用标准的平安性和命名参数,还有用于允许操作 (如只读) 的保护标志以及映射的最大容量.随后可根据来自OpenFileMapping() API的其他线程或进程使用该映射这与事件和互斥体的翻开进程是非常类似的.内存映射文件对象的另一个强大的应用是可请求系统创立一个运行映射的临时文件.该临时文件提供一个临时的区域,用于线程或进程互相发送大量数据,而不必创立或保护磁盘上的文件.利用向创立函数中发送INVALID_HANDLE_VALUE来代替真正的文件句柄,就可创立这一临时的内存映射文件;指令内核使用系统页式文件来建立支持映射的最大容量的临时数据区.为了利用文件映射对象,进程必须将对文件的
24、查看映射到它的内存空间中.也就是说,应该将文件映射对象想象为进程的第一步,在这一步中,当查看实际上允许访问的数据时,附加有共享数据的平安性和命名方式.为了获得指向内存区域的指针需要调用MapViewOfFile() API,此调用使用文件映射对象的句柄作为其主要参数.此外还有所需的访问等级 (如读-写) 和开始查看时文件内的偏移和要查看的容量.该函数返回一个指向进程内的内存的指针,此指针可有多种编程方面的应用 (但不能超过访问权限) .当结束文件映射查看时,必须用接受到的指针调用UnmapViewOfFlie() API,然后再根据映射对象调用CloseHandle() API,从而将其去除。
25、三、实验内容1. 编译运行工程SHAREMEM.DSW,观察运行结果,并阅读和分析实验程序.2.目录下的例如程序:ProcessA.exe,ProcessB.exe用三种方法实现了进程通信. (1)进程A中输入一些字符,点“利用SendMessage发送消息按钮可将消息发到进程B.(2)在进程A中输入一些字符,点“写数据到内存映像文件按钮,然后在进程B中点“从内存映像文件读数据 按钮可收到消息.(3)先在进程B中点“创立管道并接收数据 按钮,然后在进程A中输入一些字符,点“写数据到管道文件按钮可将消息发到进程B重复第3步每次可发一条消息.消息传递数据通信可参考SendMessage.txt,共
26、享内存通信可参考MemFile.txt,管道通信可参考Pipe.txt.3编写程序利用WM_COPYDATA消息机制,实现线程间的通信.进程间通信之管道每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信IPC,InterProcess Communication。如以下图所示。图 3.1 进程间通信3.1管道 管道是一种最根本的IPC机制,由pipe函数创立:#include int pipe(int f
27、iledes2);调用pipe函数时在内核中开辟一块缓冲区称为管道用于通信,它有一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes0指向管道的读端,filedes1指向管道的写端很好记,就像0是标准输入1是标准输出一样。所以管道在用户程序看起来就像一个翻开的文件,通过read(filedes0);或者write(filedes1);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返回-1。开辟了管道之后如何实现两个进程间的通信呢?比方可以按下面的步骤通信。图 3.2 管道1. 父进程调用pipe开辟管道,得到两个文件描述符指向
28、管道的两端。2. 父进程调用fork创立子进程,那么子进程也有两个文件描述符指向同一管道。3. 父进程关闭管道读端,子进程关闭管道写端。父进程可以往管道里写,子进程可以从管道里读,管道是用环形队列实现的,数据从写端流入从读端流出,这样就实现了进程间通信。例、管道#include #include #define MAXLINE 80int main(void)int n;int fd2;pid_t pid;char lineMAXLINE;if (pipe(fd) 0) perror(pipe);exit(1);if (pid = fork() 0) /* parent */close(fd0
29、);write(fd1, hello worldn, 12);wait(NULL); else /* child */close(fd1);n = read(fd0, line, MAXLINE);write(STDOUT_FILENO, line, n);return 0;使用管道有一些限制: 两个进程通过一个管道只能实现单向通信,比方上面的例子,父进程写子进程读,如果有时候也需要子进程写父进程读,就必须另开一个管道。请读者思考,如果只开一个管道,但是父进程不关闭读端,子进程也不关闭写端,双方都有读端和写端,为什么不能实现双向通信? 管道的读写端通过翻开的文件描述符来传递,因此要通信的两个进
30、程必须从它们的公共祖先那里继承管道文件描述符。上面的例子是父进程把文件描述符传给子进程之后父子进程之间通信,也可以父进程fork两次,把文件描述符传给两个子进程,然后两个子进程之间通信,总之需要通过fork传递文件描述符使两个进程都能访问同一管道,它们才能通信。使用管道需要注意以下4种特殊情况假设都是阻塞I/O操作,没有设置O_NONBLOCK标志:1. 如果所有指向管道写端的文件描述符都关闭了管道写端的引用计数等于0,而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。2. 如果有指向管道写端的文件描述符没关闭管道写端的引用计数大于0,
31、而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。3. 如果所有指向管道读端的文件描述符都关闭了管道读端的引用计数等于0,这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。4. 如果有指向管道读端的文件描述符没关闭管道读端的引用计数大于0,而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。管道的这四种特殊情况具有普遍意义。3.2 其它IPC机制
32、 进程间通信必须通过内核提供的通道,而且必须有一种方法在进程中标识内核提供的某个通道,上一节讲的管道是用翻开的文件描述符来标识的。如果要互相通信的几个进程没有从公共祖先那里继承文件描述符,它们怎么通信呢?内核提供一条通道不成问题,问题是如何标识这条通道才能使各进程都可以访问它?文件系统中的路径名是全局的,各进程都可以访问,因此可以用文件系统中的路径名来标识一个IPC通道。FIFO和UNIX Domain Socket这两种IPC机制都是利用文件系统中的特殊文件来标识的。可以用mkfifo命令创立一个FIFO文件:$ mkfifo hello$ ls -l helloprw-r-r- 1 aka
33、edu akaedu 0 2021-10-30 10:44 helloFIFO文件在磁盘上没有数据块,仅用来标识内核中的一条通道,各进程可以翻开这个文件进行read/write,实际上是在读写内核通道根本原因在于这个file结构体所指向的read、write函数和常规文件不一样,这样就实现了进程间通信。UNIX Domain Socket和FIFO的原理类似,也需要一个特殊的socket文件来标识内核中的通道,例如/var/run目录下有很多系统效劳的socket文件:$ ls -l /var/run/total 52srw-rw-rw- 1 root root 0 2021-10-30 00
34、:24 acpid.socket.srw-rw-rw- 1 root root 0 2021-10-30 00:25 gdm_socket.srw-rw-rw- 1 root root 0 2021-10-30 00:24 sdp.srwxr-xr-x 1 root root 0 2021-10-30 00:42 synaptic.socket文件类型s表示socket,这些文件在磁盘上也没有数据块。UNIX Domain Socket是目前最广泛使用的IPC机制,到后面讲socket编程时再详细介绍。现在把进程之间传递信息的各种途径包括各种IPC机制总结如下: 父进程通过fork可以将翻开文
35、件的描述符传递给子进程 子进程结束时,父进程调用wait可以得到子进程的终止信息 几个进程可以在文件系统中读写某个共享文件,也可以通过给文件加锁来实现进程间同步 进程之间互发信号,一般使用SIGUSR1和SIGUSR2实现用户自定义功能 管道 FIFO mmap函数,几个进程可以映射同一内存区 SYS V IPC,以前的SYS V UNIX系统实现的IPC机制,包括消息队列、信号量和共享内存,现在已经根本废弃 UNIX Domain Socket,目前最广泛使用的IPC机制实验四 创立线程一、实验目的1. 通过创立线程、观察正在运行的线程和终止线程的程序设计和调试操作,进一步熟悉操作系统的线程
36、概念,理解进程与线程之间的关系.2. 通过阅读和分析实验程序,学习创立线程、观察线程和终止线程的程序设计方法.二、背景知识1. 创立线程:创立线程并因而成就一个多线程程序,是以CreateThread()作为一切行动的开始.此函数的原型如下:HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThrea
37、dId );参数名称使用目的lpThreadAttributes描述施行于该新线程的security属性.NULL表示使用缺省值.dwStackSize新线程拥有自己的堆栈.0表示使用缺省大小:1MB.lpStartAddress新线程将开始的起始地址.这是一个函数指针.lpParameter此值将被传送到新线程函数作为参数dwCreationFlags允许产生一个暂时挂起的线程.默认情况是立即开始执行lpThreadId新线程的ID会被传回到这里 如果CreateThread()成功,返回一个新创立的线程的handle。如果CreateThread()失败,返回一个NULL。可以调用GetL
38、astError()获知原因.当使用CreateProcess调用时,系统将创立一个进程和一个主线程。CreateThread将在主线程的根底上创立一个新线程,大致做如下步骤: 1、在内核对象中分配一个线程标识/句柄,可供管理,由CreateThread返回该句柄。2、把线程退出码置为STILL_ACTIVE,把线程挂起计数置1 3、分配context结构 4、分配两页的物理存储以准备栈,保护页设置为PAGE_READWRITE,第2页设为PAGE_GUARD 5、 lpStartAddr和lpvThread值被放在栈顶,使它们成为传送给StartOfThread的参数 6、把context结
39、构的栈指针指向栈顶第5步指令指针指向startOfThread函数 MSDN中CreateThread原型: HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);编辑本段参数说明lpThreadAttributes:指向SECURITY_ATTRIBUTES型态的结构的指针。在Win
40、dows 98中忽略该参数。在Windows NT中,它被设为NULL,表示使用缺省值。 dwStackSize,线程堆栈大小,一般=0,在任何情况下,Windows根据需要动态延长堆栈的大小。 lpStartAddress,指向线程函数的指针,形式:函数名,函数名称没有限制,但是必须以以下形式声明: DWORD WINAPI ThreadProc (LPVOID pParam) ,格式不正确将无法调用成功。 lpParameter:向线程函数传递的参数,是一个指向结构的指针,不需传递参数时,为NULL。 dwCreationFlags :线程标志,可取值如下 CREATE_SUSPENDED
41、: 创立一个挂起的线程 0 :创立后立即激活。 lpThreadId:保存新线程的id。 返回值: 函数成功,返回线程句柄;函数失败返回false。 函数说明: 创立一个线程。 语法: hThread = CreateThread (&security_attributes, dwStackSize, ThreadProc,pParam, dwFlags, &idThread) ; 一般并不推荐使用 CreateThread函数,而推荐使用RTL 库里的System单元中定义的 BeginThread函数,因为这除了能创立一个线程和一个入口函数以外,还增加了几项保护措施。 在MFC程序中,应该
42、调用AfxBeginThread函数,在Visual C+程序中应调用_beginthreadex函数。注意:1,线程和线程句柄Handle不是一个东西,线程是在cpu上运行的,线程句柄是一个内核对象。我们可以通过句柄来操作线程,但是线程的生命周期和线程句柄的生命周期不一样的。线程的生命周期就是线程函数从开始执行到return,线程句柄的生命周期是从 CreateThread返回到你CloseHandle()。2,所有的内核对象包括线程Handle都是系统资源,用了要还的,也就是说用完后一定要closehandle关闭之,如果不这么做,你系统的句柄资源很快就用光了。3,如果你CreateThr
43、ead以后需要对这个线程做一些操作,比方改变优先级,被其他线程等待,强制TermateThread等,就要保存这个句柄,使用完了再CloseHandle。如果你开了一个线程,而不需要对它进行如何干预,CreateThread后直接CloseHandle就行了。所以,CloseHandel(ThreadHandle );只是关闭了一个线程句柄对象,表示我不再使用该句柄,即不对这个句柄对应的线程做任何干预了。并没有结束线程。2终止线程:线程结束代码可以依靠调用GetExitCodeThread()完成.BOOL GetExitCodeThread(HANDLE hThread, /*由CreateThread()传回的线程handle*/LPDWORD lpExitCode /*指向一个DWORD,用于接受结束代码*/); 如果成功,GetExitCodeThread()传回TRUE,否那么传回FALSE.如果线程已结束,那么线程的结束代码会被放在lpExitCode参数中带回来.如果线程尚未结束,lpExitCode带回来的值是STILL_ACTIVE. 如果需要用更强制性的手法结束一个线程,可以使用ExitThread().如果是VC 6下,是由于没有使用多线程的C run-time library解决方法是:debug状态
限制150内