利用多线程技术编写假脱机打印程序,并设计测试数据以验证程序的正确性。
1、界面要求:
程序采用简单的控制台界面,运行后在屏幕上显示功能菜单,列出该程序具有的功能,供用户选择。
2、功能要求:
(1)发送打印请求;
(2)查看假脱机打印队列;
(3)打印文件;
(4)退出。
用户选择功能后应该转到相应的处理程序,并在需要时显示程序的执行结果。
若用户选择(1)则提示用户输入待打印的文件名称,程序接收输入后将打印请求传送到打印队列中,并回到主菜单;
若用户选择(2)则在屏幕上列出打印队列情况,提示按任意键回到主界面;
若用户选择(3)则打印队首的文件,显示所打印的文件名称,按任意键回到主界面;
若用户选择(4)则退出程序的执行。
需要两个数据结构,一个FILE_INFO用来描述打印请求,包括文件名称和文件大小。另一个数据结构SPOOL用来描述打印请求队列。
1、线程划分myfile为了模拟假脱机打印程序,需要三个线程,主线程用于显示主菜单,接收用户的功能选择,显示打印队列情况;打印请求接收/发送线程接收用户的打印请求,并将打印请求存放到打印请求队列;打印线程用来从打印队列中取文件并将其输出到屏幕。
2、线程互斥要求三个线程都需要通过控制台终端与用户交互,因此对终端的使用要互斥,以免屏幕混乱(用互斥体h_screen_mutex实现);三个线程都要访问打印请求队列,因此对它要进行互斥操作(用互斥体h_spool_mutex实现);
3、同步要求主线程与打印请求接收/发送线程要同步,当用户选择功能(1)时,主线程要通知打印请求接收/发送线程开始接收用户请求(用初始值为0的信号量h_print实现),然后主线程要等待打印请求接收/发送线程发来接收完毕的信号(用初始值为0的信号量h_sendthread_to_mainthread实现);
主线程要与打印线程同步,当用户选择功能(3)时,主线程要通知打印线程开始打印文件(用初始值为0的信号量h_semaphore_spool实现),然后主线程要等待打印线程发来打印完毕的信号(用初始值为0的信号量h_spoolthread_to_mainthread实现);
(注意:在实际的系统中,打印线程不会等待用户从控制台发命令才开始打印,而是只要有打印请求且CPU空闲就循环不停地打印文件,直至打印队列为空,这时打印线程睡眠。本设计这样做是为了避免打印队列迅速变空。)
请求接收/发送线程和打印线程要同步,当打印队列为空时打印线程阻塞,直到请求接收/发送线程将新的请求放入队列;当打印队列满时,请求接收/发送线程阻塞,直到打印线程打印完一个文件空出新位置才能将其唤醒。这两个线程的同步遵循生产者/消费者模型,同步信号量为h_spool_empty和h_spool_full,前者跟踪空位置,后者跟踪打印请求。
为了简化程序设计,我们只考虑单机环境,而且将打印请求队列存放在内存中,而不是存放在磁盘中,另外用屏幕输出模拟实际的打印机输出。该程序包括三个线程:主线程模拟客户端程序,sendthread线程模拟打印请求接收程序,spool_thread线程模拟打印程序。
该程序使用以下全局变量:
spool_buffer是打印请求队列,互斥体h_spool_mutex用来实现对spool_buffer的互斥访问,互斥体h_screen_mutex用来实现对终端的互斥访问,h_send和h_spool_thread分别是打印请求接收/发送线程和打印线程的句柄,h_semaphore_spool和h_spoolthread_to_mainthread是主线程和打印线程之间的同步信号量,h_print和h_sendthread_to_mainthread是主线程和打印请求接收/发送线程之间的同步信号量,h_spool_full和h_spool_empty是打印线程和打印请求接收/发送线程之间的同步信号量。
该程序共有五个函数。
sendthread() //接收用户的打印请求并将其发送到打印请求队列中 spool_thread() //从打印请求队列中取待打印文件并将其输出到屏幕上 print_space() //显示若干个空格 list_spool_queue() //列出打印队列 main() //创建线程,初始化信号量,显示主菜单,根据用户选择执行相应功能
上面变量看的很混乱?没关系,直接看代码
#include#include #include #include #include #include #include #include #include #include #include #include using namespace std; HANDLE h_send; //申明打印请求接收/发送线程 HANDLE h_spool_thread; //申明打印线程 pthread_mutex_t h_screen_mutex; //对控制台终端的互斥变量 pthread_mutex_t h_spool_mutex; //对打印请求队列的互斥变量 HANDLE h_print; //主线程要通知打印请求接收/发送线程开始接收用户请求的信号量 HANDLE h_sendthread_to_mainthread; //主线程要等待打印请求接收/发送线程发来接收完毕的信号量 HANDLE h_semaphore_spool; //主线程要通知打印线程开始打印文件的信号量 HANDLE h_spolthread_to_mainthread; //主线程要等待打印线程发来打印完毕的信号量 HANDLE h_spool_empty; //显示空位置 HANDLE h_spool_full; //显示打印请求个数 int con_request=0; //请求打印时spool_queue数组的下标 int con_printf=0; //进行打印时spool_queue数组的下标 struct FILE_INFO{ //描述打印请求的结构体 string file_name; //文件名称 int file_size; //文件大小 }; struct SPOOL{ //描述打印请求队列 int spool_count=0; //打印队列中的个数 int spool_in=0; //记录下一个打印请求存放的存储位置 int spool_out=0; //记录下一个被打印文件的存储位置 FILE_INFO spool_queue[5]; //打印队列中的文件的名称和大小 }spool_buffer; void list_spool_queue(){ pthread_mutex_lock(&h_spool_mutex); pthread_mutex_lock(&h_screen_mutex); system("CLS"); printf("|序 号|---文件名---|---文件大小---|n"); for(int i=0;i<5;i++){ cout<<"| "< while(1){ WaitForSingleObject(h_print,INFINITE); //主线程发送的申请打印接收完毕 system("CLS"); if(WaitForSingleObject(h_spool_empty,5)==WAIT_TIMEOUT){ //判断有无空位置 printf("没有空位置了!!!请重新选择nn"); } else{ pthread_mutex_lock(&h_screen_mutex); system("CLS"); string name; printf("请输入你要打印的文件名称:"); getline(cin,name); pthread_mutex_unlock(&h_screen_mutex); int size=rand()%10; printf("n文件大小为%dn",size); pthread_mutex_lock(&h_spool_mutex); spool_buffer.spool_count++; spool_buffer.spool_in+=size; spool_buffer.spool_queue[con_request].file_name=name; spool_buffer.spool_queue[con_request].file_size=size; con_request++; con_request=con_request%5; if(con_request==0){ spool_buffer.spool_in=0; } ReleaseSemaphore(h_spool_full,1,NULL); //文件数加一 pthread_mutex_unlock(&h_spool_mutex); } ReleaseSemaphore(h_spolthread_to_mainthread,1,NULL); //通知主线程申请完毕 } } void spool_thread(){ while(1){ WaitForSingleObject(h_semaphore_spool,INFINITE); //主线程发送的打印请求接收完毕 if(WaitForSingleObject(h_spool_full,0)==WAIT_TIMEOUT){ printf("nn没有文件可打印!!!请重新输入n"); } else{ pthread_mutex_lock(&h_spool_mutex); pthread_mutex_lock(&h_screen_mutex); spool_buffer.spool_count--; cout< spool_buffer.spool_out=0; } pthread_mutex_unlock(&h_screen_mutex); pthread_mutex_unlock(&h_spool_mutex); ReleaseSemaphore(h_spool_empty,1,NULL); //空位置加一 } ReleaseSemaphore(h_spolthread_to_mainthread,1,NULL); //通知主线程打印完毕 } } int main(){ pthread_mutex_init(&h_screen_mutex,NULL); //对互斥变量和同步变量初始化 pthread_mutex_init(&h_spool_mutex,NULL); h_print=CreateSemaphore(NULL,0,1,NULL); //初始值为0,最大值为1 h_sendthread_to_mainthread=CreateSemaphore(NULL,0,1,NULL); h_semaphore_spool=CreateSemaphore(NULL,0,1,NULL); h_spolthread_to_mainthread=CreateSemaphore(NULL,0,1,NULL); h_spool_empty=CreateSemaphore(NULL,5,5,NULL); //初始值为5,最大值为5 h_spool_full=CreateSemaphore(NULL,0,5,NULL); //初始值为0,最大值为5 h_send=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(sendthread),NULL,0,NULL); //创建线程 h_spool_thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(spool_thread),NULL,0,NULL); //创建线程 for(int i=0;i<5;i++){ //初始化 spool_buffer.spool_queue[i].file_name=' '; spool_buffer.spool_queue[i].file_size=0; } char iin; bool end=1; while(end){ pthread_mutex_lock(&h_screen_mutex); printf("|------------------菜单显示------------------|n"); printf("|-----------1.发送打印请求-------------------|n"); printf("|-----------2.查看假脱机打印队列-------------|n"); printf("|-----------3.打印文件-----------------------|n"); printf("|-----------4.退出---------------------------|n"); printf("|-----------请输入你要执行的操作(1-4):-------|n"); scanf("%c",&iin); getchar(); system("CLS"); pthread_mutex_unlock(&h_screen_mutex); switch (iin){ case '1': ReleaseSemaphore(h_print,1,NULL); //唤醒申请打印请求 WaitForSingleObject(h_spolthread_to_mainthread,INFINITE); //线程发来的请求完毕的信号接收完毕 break; case '2': list_spool_queue(); //全部显示 break; case '3': ReleaseSemaphore(h_semaphore_spool,1,NULL); //唤醒打印 WaitForSingleObject(h_spolthread_to_mainthread,INFINITE); //线程发来的打印完毕的信号接受完毕 break; case '4': end=0; break; } } system("pause"); return 0; }



