StartupInfo.StdInput = GetStdHandle(STD_INPUT_HANDLE); StartupInfo.StdOutput = GetStdHandle(STD_OUTPUT_HANDLE); StartupInfo.StdError = GetStdHandle(STD_ERROR_HANDLE); //
// 为一个应用程序同时创建两个子进程。 //
if (CreateProcess(\ && CreateProcess(\ //
// 创建子进程成功,等待子进程运行结束。 //
WaitForSingleObject(ProcInfoOne.ProcessHandle, INFINITE); WaitForSingleObject(ProcInfoTwo.ProcessHandle, INFINITE); //
// 得到并输出子进程的退出码。 // GetExitCodeProcess(ProcInfoOne.ProcessHandle, &ulExitCode); printf(\ GetExitCodeProcess(ProcInfoTwo.ProcessHandle, &ulExitCode); printf(\ // // 关闭不再使用的句柄。 // CloseHandle(ProcInfoOne.ProcessHandle); CloseHandle(ProcInfoOne.ThreadHandle); CloseHandle(ProcInfoTwo.ProcessHandle); CloseHandle(ProcInfoTwo.ThreadHandle); } else { printf(\ nResult = 1; } return nResult; }
作用: 在eosapp.exe父进程下,为hello.exe创建两个子进程,分别等待两个子进程结束,得到退出码后关闭句柄。
结果:交替分别显示两遍\以及” Bye-bye!”。
三、思考与练习
3.在 PsCreateProcess 函数中调用了 PspCreateProcessEnvironment 函数后又先后调用了PspLoadProcessImage 和 PspCreateThread 函数,学习这些函数的主要功能。能够交换这些函数被调用的顺序吗?思考其中的原因。
答: PspCreateProcessEnvironment的主要功能是创建进程控制块,并且为进程创建地址空间和分配句柄表。PspLoadProcessImage是将进程的可执行映像加载到进程的地址空间中。PspCreateThread创建了进程的主线程。这三个函数被调用的顺序是不能够改变的。加载可执行映像之前必须已经为进程分配了地址空间,这样才能够确定可执行映像可以被加载到内
存的位置;在创建主线程之前必须已经加载过可执行映像,这样主线程才知道指令分工以及开始执行的位置。因此不能交换他们的顺序。
四、备注说明
在机房完成。
实验5 进程的同步
一、实验目的
使用 EOS 的信号量,编程解决生产者—消费者问题,理解进程同步的意义。 调试跟踪 EOS 信号量的工作过程,理解进程同步的原理。
修改 EOS 的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。
二、实验过程记录
1.
/*pc.c*/
#include \//
// 缓冲池。 //
#define BUFFER_SIZE int Buffer[BUFFER_SIZE]; //
// 产品数量。 //
#define PRODUCT_COUNT //
10
30
// 用于生产者和消费者同步的对象句柄。 //
HANDLE MutexHandle;
HANDLE EmptySemaphoreHandle; HANDLE FullSemaphoreHandle; //
// 生产者和消费者的线程函数 //
ULONG Producer(PVOID Param); ULONG Consumer(PVOID Param); //
// main 函数参数的意义:
// argc - argv 数组的长度,大小至少为 1,argc - 1 为命令行参数的数量。
// argv - 字符串指针数组,数组长度为命令行参数个数 + 1。其中 argv[0] 固定指向当前 // 进程所执行的可执行文件的路径字符串,argv[1] 及其后面的指针指向各个命令行
// 参数。
// 例如通过命令行内容 \启动进程后,hello.exe 的 main 函 // 数的参数 argc 的值为 3,argv[0] 指向字符串 \,argv[1] 指向 // 参数字符串 \,argv[2] 指向参数字符串 \。 //
int main(int argc, char* argv[]) { HANDLE ProducerHandle; HANDLE ConsumerHandle; #ifdef _DEBUG __asm(\#endif // // 创建用于互斥访问缓冲池的 Mutex 对象。 // MutexHandle = CreateMutex(FALSE, NULL); if (NULL == MutexHandle) { return 1; } // // 创建 Empty 信号量,表示缓冲池中空缓冲区数量。初始计数和最大计数都为 BUFFER_SIZE。 // EmptySemaphoreHandle = CreateSemaphore(BUFFER_SIZE, BUFFER_SIZE, NULL); if (NULL == EmptySemaphoreHandle) { return 2; } // // 创建 Full 信号量,表示缓冲池中满缓冲区数量。初始计数为 0,最大计数为 BUFFER_SIZE。 // FullSemaphoreHandle = CreateSemaphore(0, BUFFER_SIZE, NULL); if (NULL == FullSemaphoreHandle) { return 3; } //
// 创建生产者线程。 //
ProducerHandle = CreateThread( 0, Producer, NULL, 0, NULL ); if (NULL == ProducerHandle) { return 4;
// 默认堆栈大小
// 线程函数入口地址 // 线程函数参数 // 创建标志 // 线程 ID
} //
// 创建消费者线程。 //
ConsumerHandle = CreateThread( 0, Consumer, NULL, 0, NULL ); if (NULL == ConsumerHandle) { return 5; } //
// 等待生产者线程和消费者线程结束。 // WaitForSingleObject(ProducerHandle, INFINITE); WaitForSingleObject(ConsumerHandle, INFINITE); // // 关闭句柄 // CloseHandle(MutexHandle); CloseHandle(EmptySemaphoreHandle); CloseHandle(FullSemaphoreHandle); CloseHandle(ProducerHandle); CloseHandle(ConsumerHandle); return 0; } //
// 生产者线程函数。 //
ULONG Producer(PVOID Param) { int i; int InIndex = 0; for (i = 0; i < PRODUCT_COUNT; i++) { WaitForSingleObject(EmptySemaphoreHandle, INFINITE); WaitForSingleObject(MutexHandle, INFINITE); printf(\ Buffer[InIndex] = i; InIndex = (InIndex + 1) % BUFFER_SIZE; ReleaseMutex(MutexHandle); ReleaseSemaphore(FullSemaphoreHandle, 1, NULL); // // 休息一会。每 500 毫秒生产一个数。
// Sleep(500); } return 0; } //
// 消费者线程函数。 //
ULONG Consumer(PVOID Param) { int i; int OutIndex = 0; for (i = 0; i < PRODUCT_COUNT; i++) { WaitForSingleObject(FullSemaphoreHandle, INFINITE); WaitForSingleObject(MutexHandle, INFINITE); printf(\ OutIndex = (OutIndex + 1) % BUFFER_SIZE; ReleaseMutex(MutexHandle); ReleaseSemaphore(EmptySemaphoreHandle, 1, NULL); // }
// 休息一会儿。让前 10 个数的消费速度比较慢,后面的较快。 // if (i < 10) { Sleep(2000); } else { Sleep(100); } }
return 0;
作用:演示生产者、消费者问题。创建Mutex对象->创建Empty信号量对象->创建Full信号量对象->创建生产者线程->创建消费者线程->等待生产者线程和消费者线程结束->关闭句柄 结果: