#include
static LPCTSTR g_szMutexName=\//创建当前进程的克隆进程的简单方法 void StartClone()
{ TCHAR szFilename[MAX_PATH]; //获得当前可执行文件的文件名
GetModuleFileName(NULL,szFilename,MAX_PATH);
//格式化子进程的命令行,指明是一个EXE文件和子进程 TCHAR szCmdLine[MAX_PATH];
sprintf(szCmdLine,\ //子进程的启动信息结构 STARTUPINFO si;
ZeroMemory(reinterpret_cast
PROCESS_INFORMATION p; //说明一个返回的子进程信息结构 //利用同样的可执行文件名和命令行创建进程,并指明是一个子进程 BOOL bCreateOK=CreateProcess( szFilename, //产生的应用程序的名称 szCmdLine, //指定创建一个子进程的符号标识 NULL, //默认的进程安全性 NULL, //默认的线程安全性 FALSE, //不继承句柄 CREATE_NEW_CONSOLE,/ /创建新窗口,使输出更直观 NULL, //新环境 NULL, //当前目录 &si, //启动信息结构 &p); //返回的进程信息 //关闭子进程 if(bCreateOK) {
CloseHandle(p.hProcess); CloseHandle(p.hThread); } }
void Parent() {
//创建“自杀”互斥体
HANDLE hMutexSuicide=CreateMutex( NULL, //默认的安全性
TRUE, //创建者是互斥体的最初拥有者 g_szMutexName); //为互斥体命名 if(hMutexSuicide!=NULL) {
printf(\.\\n\
StartClone(); //创建一个子进程 Sleep(5000); //暂停(5秒)
printf(\.\\n\
ReleaseMutex(hMutexSuicide); //通知子进程”杀”掉自身 CloseHandle(hMutexSuicide); //消除互斥体句柄 } }
void Child()
{ //打开“自杀”互斥体
HANDLE hMutexSuicide=OpenMutex( SYNCHRONIZE, //打开用于同步 FALSE, //不需要向下传递 g_szMutexName); //互斥体名称 if(hMutexSuicide!=NULL) {
printf(\.\\n\ WaitForSingleObject(hMutexSuicide,INFINITE); //等待子进程释放互斥体 //准备好终止,清除句柄
printf(\.\\n\ CloseHandle(hMutexSuicide); } }
int main(int argc,char * argv[]) { //决定其行为是父进程还是子进程 if(argc>1&&strcmp(argv[1],\ { Child();} else { Parent();} return 0; }
实验内容
1.参照例2-2,编写一个程序,利用进程句柄来获得当前运行进程的优先级。 2.运行例2-3,记录运行结果(不少于5个进程的信息),并描述该程序的功能。 3.运行例2-4,记录运行结果,并描述该程序的功能。
4.参照例2-5,编写一个程序,给出运行进程的操作系统的版本号。
5.用命令行的方式运行2次例2-6(每次命令行参数不同:命令行中是否包含“child”参数),记录运行结果,并描述该程序的功能。
6.有能力的同学选做:参照例2-6,编写一个程序,通过创建进程来执行一个命令列表(命令列表中有3个应用程序的程序名,这些程序运行一段时间后被中止退出),并输出每个进程(这3个应用程序)的执行时间。
实验三 线程同步和调度
(Windows2000)
实验目的
通过创建线程、分配线程优先级和终止线程的程序设计和调试操作,进一步熟悉操作系统的线程概念,理解Windows 2000线程的生命周期。
通过对事件、互斥体对象和信号量的了解,加深对Windows 2000线程同步的理解。
实验预备知识
Windows 2000提供的常用对象可分成3类:核心应用服务、线程同步和线程间通信。其中,开发人员可以使用线程同步对象来协调线程和进程的工作,以使其共享信息并执行任务。此类对象包括互锁数据、临界段、事件、互斥体和信号等。此外,还可以使用系统所提供的线程间通讯类内核对象来实现同一进程或跨进程的线程之间互相发送信息,包括文件、文件映射、邮件槽和命名管道等,其中最常用的是文件和文件映射。这类对象允许一个线程很容易地向同一进程或其他进程中的另一线程发送信息。
Windows 2000是一个抢先式多任务操作系统,提供了对多线程进程的支持。这样,开发人员可以创建一种应用程序,将必须完成的工作任务划分为逻辑小块,而将每个小块任务再分配给线程来完成。在Windows 2000中,这个组件是微内核。微内核负责了解哪些线程当前想要占用CPU周期以及正在占用CPU时间的情况,并把结果告诉每个执行的线程。系统使用调度策略分配其CPU周期,微内核通过控制CPU、暂停正在运行的线程以及恢复调度的线程来实现调度。为了更好地做到这一点,需要了解Windows 2000的线程对象以及如何使用这种线程对象。
一、 创建新线程
线程是第一级内核对象,它起源于微内核。创建线程的进程通过对象句柄来引用线程。每个线程对象表示包括命令指针和地址转换表的一组注册信息,可以被加载到CPU中。活动线程对象是处于无信号状态的,可以是挂起的,处于准备运行状态或运行状态。
创建新进程时,同时创建该进程的主线程。线程对象句柄可从CreateProcess()的PROCESS_INFORMATl0N中返回。进程对象的创建过程就是线程对象的创建过程。
使用CreateThread()API可启动新线程的执行,该API可在系统要执行线程列表中产生一个新项,并把创建线程的标识符(thread identifier,TID)传递给调用程序,并保存到PROCESS_INFORMATION结构中。
在创建一个线程时,一种好的方法是将其行为封装到c++的类中。这可将线程例程隐藏为静态成员,把对象指针作为参数传递,通过调用非静态的方法来简化线程例程。 1.相关API函数说明 (1)CreateThread
函数功能:该函数可创建一个在调用进程的地址空间中执行的线程。 函数格式:
HANDLE CreateThread(
LPSECURIT_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_STAR_ROUTINE lpStartAddress, LPVOID lpParameter,
DWORD dwCreationFlags, LPDWORD lpThreadID); 参数:
·lpThreadAttributes
指定了应用于新线程的安全属性参数,包括访问权和继承权等。该参数描述了与新对象相关的安全性,这个信息告诉系统哪些账号允许线程对象访问,哪些账号拒绝线程对象访问。若lpThreadAttributes的值为NULL,则线程获得一个默认的安全性描述符。 ·dwstackSize
定义线程将接受的堆栈长度,堆栈长度通过链接程序从进程EXE 文件中设置。设置时,进程一般通过把dwStackSize参数设置为0作为其默认值。如果使用进程的默认堆栈容量,则其值为0。
·lpStartAddress
指定线程执行的函数的开始地址,一旦该函数退出,那么线程将终止(这个函数通常称为TreadProc)。 ·lpParameter
定义一个传递给该线程的32位值。 ·dwCreationFlags
定义控制进程创建标志。若该参数为CREATE_SUSPENDED时,创建的线程为挂起态,并且直到ResumeThread函数调用时才能运行。若该参数为O,则该线程在创建后立即执行。 ·lpThreadID
指向一个32位值,接收该线程标志符(thread identifier,TID)。
返回值:若函数调用成功,返回新创建线程的句柄,并将线程标识符保存到调用程序的PROCESS_INFORMATION结构中;若函数调用失败,返回值为NULL。
备注:新进程的句柄创建时设为THREAD_ALL_ACCESS访问权限。若未提供安性描述符,则该句柄可被任何要求一个线程对象句柄的函数所使用。若提供了安全性描述符,则以后使用该句柄时,将在授权访问以前执行访问检查。若访问检查拒绝访问,则请求进程不能使用该句柄获得对该线程的访问。
线程从lpStartAddress参数定义的函数处开始执行。若该函数返回,系统将默认地以调用ExitThread函数的方法终止该线程。使用GetExitcodeThread函数来获得线程的返回值。
线程创建时拥有THREAD_PRIORITY_NORMAL优先线。使用GetThreadPriority和SetThreadPriority函数可以获得和设置线程的优先权值。
一个线程终止时,该线程对象被设为有信号状态,以满足在该对象上等待的所有进程。 一个线程对象始终存在于系统中,直到该线程终止,且该线程所有的句柄都已通过调用CloseHandle函数关闭。
(2)GetThreadPriority
函数功能:该函数可用来获得指定线程的优先级。 函数格式:
int GetThreadPriority(HANDLE hThread); 参数:hThread指定线程的句柄。
返回值:如果函数调用成功,返回值为线程的优先级;否则返回值为
THREA_QUERY_INFORMATION。
(3)SetThreadPriority
函数功能:该函数可用来设置指定线程的优先级。 函数格式:
BOOL SetThreadPriority(HANDLE hThread,int nPriority); 参数:hThread指定线程的句柄;nPriority指定线程的优先级。 返回值:如果函数调用成功,返回非零值;否则返回值为零。 (4)GetExitCodeThread
函数功能:该函数可用来判断某一个线程当前是否处于运行状态。如果线程仍在运行,返回的状态为STILL_ACTIVE。
函数格式:
BOOL GetExitCodeThread(HANDLE hThread,LPWORD lpwdExitCode);
参数:hThread指定线程对象句柄,该句柄必须拥有THREAD_QUERY_INFORMATION权限,以便返回终止状态。lpwdExitCode指定接收线程的终止状态。如果线程已终止,则为TerminateThread或ExitThread中传递的值,否则为sTILL_ACTIVE。
返回值:如果函数调用成功则返回TRUE,否则返回FALSE。 2.创建线程的实例程序
为了更好地理解创建线程的技术,下面给出一个例子。 例3-1:创建新线程 #include
// 封装创建工作线程的类 class CWorkerThread {
public:
CWorkerThread(LPCTSTR SzName):
m_szName(SzName),m_hThread(INVALID_HANDLE_VALUE) {
// 创建新线程并令其启动 m_hThread=CreateThread( NULL, // 默认的安全性 0, // 默认堆栈
ThreadProc, // 类范围内的线程proc
reinterpret_cast
virtual ~CWorkerThread(){CloseHandle(m_hThread);} // 简单的等待线程完成的方法
virtual void WaitForCompletion() {
WaitForSingleObject(m_hThread,INFINITE); }
protected:
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库14-15(2)实验指导书(6)在线全文阅读。
相关推荐: