简单的多线程编程_同步与互斥问题

来源:互联网 发布:印度与中国 知乎 编辑:程序博客网 时间:2024/06/05 04:03

大纲:

零。关于同步与互斥的多线程编程(一般思路)

        1. 申请“信号量”句柄,初始化信号量。 (HANDLE ...)

        2. 创建使用上线程的函数(函数中需要用到信号量)。(CreateSemaphore(...))

        3. 创建线程(创建线程时用上第二步的函数)。(CreateThread(...))

        4. 等待结束线程。(WaitForSingleObject(...))

        5. 关闭句柄。(CloseHandle(...))

 

一。放水果问题

       1. 程序演示

       2. 程序运行效果

       3. 运行结果简要分析

 

二。生产者与消费者问题

       1. 程序演示

       2. 程序运行效果

       3. 运行结果简要分析

 

内容:

一。放水果问题

       1. 程序演示

[cpp] view plain copy
 print?
  1. // fruitThread.cpp  
  2.   
  3. /** 
  4.  * 题目要求: 
  5.  * 桌子上有一只盘子,只允许存放一个水果,父亲专向盘中放水果,母亲专向盘中放桔子, 
  6.  * 儿子专等吃盘里的桔子,女儿专等吃盘里的苹果。只要盘子空,则父亲母亲可向盘中放水果, 
  7.  * 仅当盘中有自己需要的水果时,儿子或女儿可从中取出。 
  8.  * 请给出四人之间的同步关系,并用PV操作实现四人正确活动的程序。 
  9.  **/  
  10.   
  11.   
  12. #include <iostream>  
  13. #include <windows.h>  
  14.   
  15. using namespace std;  
  16.   
  17. // 信号量句柄声明  
  18. HANDLE emptyMutex;  
  19. HANDLE orangeMutex;  
  20. HANDLE fruitMutex;  
  21.   
  22. int main()  
  23. {  
  24.     // 创建需要用到的信号量  
  25.     // 函数的第2个参数表示信号量的初始值,第3个参数表示信号量的最大数值  
  26.     emptyMutex = CreateSemaphore(NULL, 1, 1, NULL);  
  27.     orangeMutex = CreateSemaphore(NULL, 0, 1, NULL);  
  28.     fruitMutex = CreateSemaphore(NULL, 0, 1, NULL);  
  29.   
  30.     // 声明线程需要用到的函数  
  31.     DWORD WINAPI fatherThread(LPVOID IpParameter);  
  32.     DWORD WINAPI motherThread(LPVOID IpParameter);  
  33.     DWORD WINAPI sonThread(LPVOID IpParameter);  
  34.     DWORD WINAPI daughterThread(LPVOID IpParameter);  
  35.   
  36.   
  37.     cout << "盘子取放水果游戏开始." << endl;  
  38.   
  39.     // 创建线程  
  40.     HANDLE fThread = CreateThread(NULL, 0, fatherThread, NULL, 0, NULL);  
  41.     HANDLE mThread = CreateThread(NULL, 0, motherThread, NULL, 0, NULL);  
  42.     HANDLE sThread = CreateThread(NULL, 0, sonThread, NULL, 0, NULL);  
  43.     HANDLE dThread = CreateThread(NULL, 0, daughterThread, NULL, 0, NULL);  
  44.   
  45.     // 等待线程结束  
  46.     WaitForSingleObject(fThread, INFINITE);  
  47.     WaitForSingleObject(mThread, INFINITE);  
  48.     WaitForSingleObject(sThread, INFINITE);  
  49.     WaitForSingleObject(dThread, INFINITE);  
  50.   
  51.     // 关闭句柄  
  52.     CloseHandle(fThread);  
  53.     CloseHandle(mThread);  
  54.     CloseHandle(sThread);  
  55.     CloseHandle(dThread);  
  56.   
  57.     CloseHandle(emptyMutex);  
  58.     CloseHandle(orangeMutex);  
  59.     CloseHandle(fruitMutex);  
  60.   
  61.     cout << "\n盘子取放水果游戏结束." << endl;  
  62.     system("pause");  
  63.     return 0;  
  64. }  
  65.   
  66. DWORD WINAPI fatherThread(LPVOID IpParameter)  
  67. {  
  68.     for(int i = 0; i < 5; ++i){  
  69.         WaitForSingleObject(emptyMutex, INFINITE);  // P操作  
  70.         // 开始临界区  
  71.         cout << "\nFather往盘中放一个苹果\n";  
  72.         // 结束临界区  
  73.         ReleaseSemaphore(fruitMutex, 1, NULL);  // V操作  
  74.     }  
  75.     return 0;  
  76. }  
  77.   
  78. DWORD WINAPI motherThread(LPVOID IpParmeter)  
  79. {  
  80.     for(int i = 0; i < 5; ++i){  
  81.         WaitForSingleObject(emptyMutex, INFINITE);  // P操作  
  82.         // 开始临界区  
  83.         cout << "\nMother往盘中放一个桔子\n";  
  84.         // 结束临界区  
  85.         ReleaseSemaphore(orangeMutex, 1, NULL); // V操作  
  86.     }  
  87.     return 0;  
  88. }  
  89.   
  90. DWORD WINAPI sonThread(LPVOID IpParmeter)  
  91. {  
  92.     for(int i = 0; i < 5; ++i){  
  93.         WaitForSingleObject(orangeMutex, INFINITE); // P操作  
  94.         // 开始临界区  
  95.         cout << "Son往盘中取一个桔子\n";  
  96.         // 结束临界区  
  97.         ReleaseSemaphore(emptyMutex, 1, NULL);  // V操作  
  98.     }  
  99.     return 0;  
  100. }  
  101.   
  102. DWORD WINAPI daughterThread(LPVOID IpParmeter)  
  103. {  
  104.     for(int i = 0; i < 5; ++i){  
  105.         WaitForSingleObject(fruitMutex, INFINITE);  // P操作  
  106.         // 开始临界区  
  107.         cout << "Daughter往盘中取一个苹果\n";  
  108.         // 结束临界区  
  109.         ReleaseSemaphore(emptyMutex, 1, NULL);  // V操作  
  110.     }  
  111.     return 0;  
  112. }  


 

       2. 程序运行效果

 

       3. 运行结果简要分析

      首先由结果可以看见的是,它们已经按题目要求输出了,Father放入的是苹果,Mother放入的是Orange,而Son取的是Orange,Daughter取的是苹果,这里一共有十次的放入操作,分别是五次父亲的放入及五次母亲的放入,还有十次的取出操作,分别是女儿的取出还有儿子的取出,而这些放入与取出,都遵循着这么一个规律,“取”建立在“放”之前,而且必是一放一取,也就是满足了题目要求中的盘子一次只能有一个水果的要求。

 

二。生产者与消费者问题

      

1. 程序演示

[cpp] view plain copy
 print?
  1. // ProducerAndConsumerThread.cpp  
  2.   
  3. /** 
  4.  * 题目要求: 
  5.  * 有两组进程共享一个环形的缓冲池。一组进程被称为生产者,另一组进程被称为消费者。 
  6.  * 缓冲池是由若干个(实验中可假设为4个)大小相等的缓冲区组成的,每个缓冲区可以容纳 
  7.  * 一个产品。生产者时空程不断地将生产的产品放入缓冲池,消费者进程不断地将产品从缓冲池 
  8.  * 中取出。用PV操作实现和生产者消费者正确活动的程序。 
  9.  **/  
  10.   
  11.   
  12. #include <iostream>  
  13. #include <string.h>  
  14. #include <windows.h>  
  15.   
  16. using namespace std;  
  17.   
  18. // 信号量句柄声明  
  19. HANDLE emptyMutex;  
  20. HANDLE fullMutex;  
  21. HANDLE bufferMutex;  
  22.   
  23. // 缓冲区及相关数目计算变量声明  
  24. char buffer[] = "123456";  
  25. const int maxBufferNumber = strlen(buffer) - 1;  
  26. int nowUsingBufferNumber(0);  
  27.   
  28. int main()  
  29. {  
  30.     // 创建需要用到的信号量  
  31.     // 函数的第2个参数表示信号量的初始值,第3个参数表示信号量的最大数值  
  32.     emptyMutex = CreateSemaphore(NULL, maxBufferNumber, maxBufferNumber, NULL);  
  33.     fullMutex = CreateSemaphore(NULL, 0, maxBufferNumber, NULL);  
  34.     bufferMutex = CreateSemaphore(NULL, 1, 1, NULL);  
  35.   
  36.     // 声明线程需要用到的函数  
  37.     DWORD WINAPI ProducerThread(LPVOID IpParameter);  
  38.     DWORD WINAPI ConsumerThread(LPVOID IpParameter);  
  39.   
  40.     cout << "-> 生产者、消费者问题开始.\n" << endl;  
  41.   
  42.     // 创建线程  
  43.     HANDLE pThread = CreateThread(NULL, 0, ProducerThread, NULL, 0, NULL);  
  44.     HANDLE cThread = CreateThread(NULL, 0, ConsumerThread, NULL, 0, NULL);  
  45.   
  46.     // 等待线程结束  
  47.     WaitForSingleObject(pThread, INFINITE);  
  48.     WaitForSingleObject(cThread, INFINITE);  
  49.   
  50.     // 关闭句柄  
  51.     CloseHandle(pThread);  
  52.     CloseHandle(cThread);  
  53.   
  54.     CloseHandle(emptyMutex);  
  55.     CloseHandle(fullMutex);  
  56.     CloseHandle(bufferMutex);  
  57.   
  58.     cout << "\n-> 生产者、消费者问题结束." << endl;  
  59.     system("pause");  
  60.     return 0;  
  61. }  
  62.   
  63.   
  64.   
  65. DWORD WINAPI ProducerThread(LPVOID IpParmeter)  
  66. {  
  67.     int n = 10;  
  68.     while(n--){  
  69.         WaitForSingleObject(emptyMutex, INFINITE); // P(缓冲区上有空位)  
  70.   
  71.         WaitForSingleObject(bufferMutex, INFINITE); // P(资源未被占用)  
  72.         nowUsingBufferNumber = (nowUsingBufferNumber + 1) % maxBufferNumber;  
  73.         buffer[nowUsingBufferNumber] = nowUsingBufferNumber + 'A';  
  74.         cout << "Hey, 生产者正在为你放入第" << nowUsingBufferNumber << "个资源"  
  75.              << ",资源的内容为" << buffer[nowUsingBufferNumber]  
  76.              << "  (  put put put .... )" << endl;  
  77.         ReleaseSemaphore(bufferMutex, 1, NULL); // V(资源占用完毕)  
  78.   
  79.         ReleaseSemaphore(fullMutex, 1, NULL);   // V(释放满的资源信号量)  
  80.     }  
  81.     return 0;  
  82. }  
  83.   
  84. DWORD WINAPI ConsumerThread(LPVOID IpParameter)  
  85. {  
  86.      int n = 10;  
  87.      while(n--){  
  88.         WaitForSingleObject(fullMutex, INFINITE);   // P(缓冲区上有资源可提取)  
  89.   
  90.          WaitForSingleObject(bufferMutex, INFINITE); // P(资源未被占用)  
  91.          cout << "Yoo, 消费者正在取出第" << nowUsingBufferNumber << "个资源"  
  92.              << ",资源的内容为" << buffer[nowUsingBufferNumber]  
  93.              << "  (get...)" << endl;  
  94.         nowUsingBufferNumber = (nowUsingBufferNumber - 1 + maxBufferNumber) % maxBufferNumber;  
  95.         ReleaseSemaphore(bufferMutex, 1, NULL); // V(资源占用完毕)  
  96.   
  97.          ReleaseSemaphore(emptyMutex, 1, NULL);   // V(释放空的资源信号量  
  98.        }  
  99.     return 0;  
  100. }  


   2. 程序运行效果

 

  3. 运行结果简要分析

        可以看见的是,这里共执行了十次的生产者放入资源操作与十次的消费者取出资源的操作,在缓冲池有数据的时候,消费者可以从缓冲区取出资源,刚刚开始时,生产者先放入资源“B”,由于缓冲区未满,所以生产者仍可继续再放入资源“C”,这时,虽然生产者可以继续放入资源,但是,由于消费者线程先执行操作了,从缓冲区中取出资源,所以,生产者的放入资源操作会在消费者的取出操作完成后再进行,按照生产者缓冲区有非满且非在进行操作则可放,消费者缓冲区非空且非在进行操作则可取的原则,这两个进行不断地运行循环,直到完成循环中设定的次数,最后,由于程序中的生产者与消费者的操作数目设定相同,所以,到最后会将缓冲区清空后退出程序。


http://blog.csdn.net/neicole/article/details/7459000

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 word批注不显示怎么办 wps怎么办把修订取消 审阅密码忘了怎么办 psv关机后怎么办刷 被螃蟹扎了怎么办 被海鲜划伤出血怎么办 海域使用证缴纳金没交怎么办 海峡中线 金门海域怎么办 对工作失去热情怎么办 取款机多出钱怎么办 风扇声音很响怎么办 稳压器输出没电怎么办 稳压器不稳10压怎么办 dnf凯蒂不见了怎么办 马桶里掉进塑料瓶盖怎么办 塑料瓶子盖子打不开怎么办 按压瓶盖坏了怎么办 瓶盖拧错位了怎么办 红酒盖子开不了怎么办 胶盖罐头打不开怎么办 玻璃瓶的塑料盖打不开怎么办 香水按压不出来怎么办 电高压锅盖子打不开怎么办 杯子螺口错位怎么办 散粉盖子扭不开怎么办 玻璃瓶饮料盖子打不开怎么办 玻璃瓶玻璃盖子打不开怎么办 美甲没有胶水怎么办 按压式瓶盖打不开怎么办 睫毛胶水瓶盖打不开怎么办 玻璃杯盖子滑丝怎么办 瓶盖滑扣了怎么办 胶水瓶口被塞住怎么办 美林盖子打不开怎么办 美林瓶盖打不开怎么办 泰诺瓶盖打不开怎么办 玻璃罐头瓶盖打不开怎么办 塑料罐头瓶盖打不开怎么办 喷笔壶盖打不开怎么办 陶瓷壶盖卡住了怎么办 贝德玛瓶盖摔坏怎么办