您的位置:首页 > 职场人生

线程面试题之五:放水果问题

2014-08-14 16:15 1216 查看
桌上有一空盘,允许存放一只水果。爸爸可向盘中放苹果,也可向盘中放桔子,儿子专等吃盘中的桔子,女儿专等吃盘中的苹果。规定当盘空时一次只能放一只水果供吃者取用,请用P、V原语实现爸爸、儿子、女儿三个并发线程的同步。(南京大学计算机考研真题)
(注:在写本篇学习笔记时,本人学习和参考了网络文章,并做了借鉴,感谢各位前辈的分享。如果本文对您有所帮助,您可以随意分享,如果发现文中有误,也请指教,谢谢。本文用到的调试工具:Microsoft
Visual Studio 10,操作系统:Windows 7)

我们首先考虑同步情况即所有“等待”情况:
第一,爸爸要等待盘子为空。
第二,儿子要等待盘中水果是桔子。
第三,女儿要等待盘中水果是苹果。
接下来来考虑要互斥处理的资源,看起来盘子好像是要作互斥处理的,但由于题目中的爸爸、儿子、女儿均只有一个,并且他们访问盘子的条件都不一样,所以他们根本不会同时去访问盘子,因此盘子也就不用作互斥处理了。分析至此,这个题目已经没有难度了,下面用PV原语给出答案:
先设置三个信号量,信号量Orange表示盘中有桔子,初值为0。信号量Apple表示盘中有苹果,初值为0。信号量EmptyDish表示盘子为空,初值为1。三个人的操作流程如下所示:
1.爸爸
P(EmptyDish)
if (rand()%2==0)
{
放桔子
V(Orange)
}
else
{
放苹果
V(Apple)
}
2.儿子
P(Orange)
取桔子
V(EmptyDish)
3.女儿
P(Apple)
取苹果
V(EmptyDish)
以下为多线程实现的取水果源码:
#include "stdafx.h"
#include "process.h"
#include "windows.h"
#include "time.h"

HANDLE g_hEmptyDish;
HANDLE g_hFullApple;
HANDLE g_hFullOrange;
HANDLE g_hEvent;

const int SLEEP_TIMES = 200;    // 睡眠时间(ms)
const int RAND_MAX_NUM = 99999; // 随机数种子
const int FULL_TIMES = 10;      // 循环总数
int g_iTimes = 1;               // 循环次数
int g_iFruit = 0;
BOOL g_bFlag = FALSE;

// 设置控制台输出颜色
BOOL SetConsoleColor(WORD wAttributes)
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE)
{
return FALSE;
}
return SetConsoleTextAttribute(hConsole, wAttributes);
}

unsigned int __stdcall ThreadFatherFunc(LPVOID pM)
{
int iRandNum = 0;

srand((unsigned)time(NULL));
while (TRUE)
{
WaitForSingleObject(g_hEmptyDish,INFINITE);
Sleep(SLEEP_TIMES);
iRandNum = rand()%RAND_MAX_NUM;
if (iRandNum%2 == 0)
{
g_iFruit++;
SetConsoleColor(FOREGROUND_GREEN|FOREGROUND_INTENSITY);
printf("父亲向盘中放入%d橘子\n",g_iFruit);
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
g_iTimes++;
ReleaseSemaphore(g_hFullOrange,1,NULL);
if (g_iTimes == FULL_TIMES)
{
break;
}
}
else
{
g_iFruit++;
SetConsoleColor(FOREGROUND_RED|FOREGROUND_INTENSITY);
printf("父亲向盘中放入%d苹果\n",g_iFruit);
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
g_iTimes++;
ReleaseSemaphore(g_hFullApple,1,NULL);
if (g_iTimes == FULL_TIMES)
{
break;
}
}
}
printf("父亲发现循环次数足够,游戏结束,退出线程。\n");

return 0;
}

unsigned int __stdcall ThreadChildrenFunc(LPVOID pM)
{
int * num = (int *)pM;

if (*num == 1)
{
SetEvent(g_hEvent);
while (TRUE)
{
WaitForSingleObject(g_hFullOrange,INFINITE);
Sleep(SLEEP_TIMES);
if (g_bFlag)
{
break;
}
SetConsoleColor(FOREGROUND_GREEN);
printf("  儿子从盘中取出%d橘子\n",g_iFruit);
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
g_iFruit--;
if (g_iTimes == FULL_TIMES)
{
// 当哥哥发现循环次数足够,则通知妹妹退出线程
g_bFlag = TRUE;
ReleaseSemaphore(g_hFullApple,1,NULL);
break;
}
ReleaseSemaphore(g_hEmptyDish,1,NULL);
}
printf("儿子收到消息,游戏结束,退出线程。\n");
}
else
{
SetEvent(g_hEvent);
while (TRUE)
{
WaitForSingleObject(g_hFullApple,INFINITE);
Sleep(SLEEP_TIMES);
if (g_bFlag)
{
break;
}
SetConsoleColor(FOREGROUND_RED);
printf("  女儿从盘中取出%d苹果\n",g_iFruit);
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
g_iFruit--;
if (g_iTimes == FULL_TIMES)
{
// 当妹妹发现循环次数足够,则通知哥哥退出线程
g_bFlag = TRUE;
ReleaseSemaphore(g_hFullOrange,1,NULL);
break;
}
ReleaseSemaphore(g_hEmptyDish,1,NULL);
}
printf("女儿收到消息,游戏结束,退出线程。\n");
}
return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
printf("-------------------------------\n");
printf("   取水果问题的多线程实现\n");
printf("-------------------------------\n");
int i = 0;
int THD_NUM = 3;
HANDLE hThread[3];

g_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
g_hEmptyDish  = CreateSemaphore(NULL,1,1,NULL);
g_hFullApple  = CreateSemaphore(NULL,0,1,NULL);
g_hFullOrange = CreateSemaphore(NULL,0,1,NULL);

hThread[0] = (HANDLE)_beginthreadex(NULL,0,ThreadFatherFunc,NULL,0,NULL);
for (i=1;i<THD_NUM;i++)
{
hThread[i] = (HANDLE)_beginthreadex(NULL,0,ThreadChildrenFunc,&i,0,NULL);
WaitForSingleObject(g_hEvent,INFINITE);
}

WaitForMultipleObjects(THD_NUM, hThread, TRUE, INFINITE);
for (i=0;i<THD_NUM;i++)
{
CloseHandle(hThread[i]);
}

CloseHandle(g_hEvent);
CloseHandle(g_hEmptyDish);
CloseHandle(g_hFullApple);
CloseHandle(g_hFullOrange);

getchar();

return 0;
}

运行结果为:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: