题目来源:秒杀多线程第一篇 多线程笔试面试题汇总
/********************************/
第五题(Google面试题)
有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推………现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:
A:1 2 3 4 1 2….
B:2 3 4 1 2 3….
C:3 4 1 2 3 4….
D:4 1 2 3 4 1….
请设计程序。
/********************************/
以下是本人作答部分。
#include "stdio.h"
#include <WINDOWS.H>
#define BUF_LEN 50
#define THREAD_NUM 4
#define EVENT_NUM 4
char g_ABuf[BUF_LEN] = {0}; //模拟文件 A 下同
int g_ABufTail = 0;
char g_BBuf[BUF_LEN] = {0};
int g_BBufTail = 0;
char g_CBuf[BUF_LEN] = {0};
int g_CBufTail = 0;
char g_DBuf[BUF_LEN] = {0};
int g_DBufTail = 0;
/*
* 0 [0][1][2][3] 第0组用于同步对文件A的写操作,依次类推
* 1 [0][1][2][3]
* 2 [0][1][2][3]
* 3 [0][1][2][3]
*/
HANDLE g_EventHandle[EVENT_NUM][EVENT_NUM] = {INVALID_HANDLE_VALUE}; //同步四个文件写入操作
DWORD g_dwThreadID[THREAD_NUM] = {0};//线程ID
HANDLE g_ExitThreadHandle = INVALID_HANDLE_VALUE; //等待退出线程
HANDLE g_ThreadExitHandle[THREAD_NUM] = {INVALID_HANDLE_VALUE};//线程退出,通知主线程
DWORD WINAPI ThreadFunc(LPVOID lparam);
void WriteABuffer(DWORD dwTmp);//文件A写操作 下同
void WriteBBuffer(DWORD dwTmp);
void WriteCBuffer(DWORD dwTmp);
void WriteDBuffer(DWORD dwTmp);
CRITICAL_SECTION g_Critical;
void WriteABuffer(DWORD dwTmp)
{
//使用临界区对文件A的访问加锁,使多个线程可以互斥访问 下同
EnterCriticalSection(&g_Critical);
if (g_ABufTail >= BUF_LEN)
{
LeaveCriticalSection(&g_Critical);
return ;
}
g_ABuf[g_ABufTail++] = (char)dwTmp + (char)0x31;
Sleep(10);
LeaveCriticalSection(&g_Critical);
}
void WriteBBuffer(DWORD dwTmp)
{
EnterCriticalSection(&g_Critical);
if (g_BBufTail >= BUF_LEN)
{
LeaveCriticalSection(&g_Critical);
return ;
}
g_BBuf[g_BBufTail++] = (char)dwTmp + (char)0x31;
Sleep(20);
LeaveCriticalSection(&g_Critical);
}
void WriteCBuffer(DWORD dwTmp)
{
EnterCriticalSection(&g_Critical);
if (g_CBufTail >= BUF_LEN)
{
LeaveCriticalSection(&g_Critical);
return ;
}
g_CBuf[g_CBufTail++] = (char)dwTmp + (char)0x31;
Sleep(5);
LeaveCriticalSection(&g_Critical);
}
void WriteDBuffer(DWORD dwTmp)
{
EnterCriticalSection(&g_Critical);
if (g_DBufTail >= BUF_LEN)
{
LeaveCriticalSection(&g_Critical);
return ;
}
g_DBuf[g_DBufTail++] = (char)dwTmp + (char)0x31;
Sleep(15);
LeaveCriticalSection(&g_Critical);
}
DWORD WINAPI ThreadFunc( LPVOID lparam )
{
DWORD ldw_ThreadID = (DWORD)lparam;
DWORD dwRt = 0;
DWORD dwii = 0;
while(1)
{
dwRt = WaitForSingleObject(g_ExitThreadHandle,0); //等待主线程通知何时退出
if (WAIT_OBJECT_0 == dwRt)
{
break;
}
dwii = (THREAD_NUM + ldw_ThreadID - 1)%THREAD_NUM; //计算需等待的前一个事件对象的下标
dwRt = WaitForSingleObject(g_EventHandle[0][dwii],0);//对于文件A,本线程需等待前一个线程的信号
if (WAIT_OBJECT_0 == dwRt)
{
WriteABuffer(ldw_ThreadID);
SetEvent(g_EventHandle[0][ldw_ThreadID]);//将本线程事件对象设置为有信号状态,以此通知下一个线程对文件A写操作
}
dwRt = WaitForSingleObject(g_EventHandle[1][dwii],0);
if (WAIT_OBJECT_0 == dwRt)
{
WriteBBuffer(ldw_ThreadID);
SetEvent(g_EventHandle[1][ldw_ThreadID]);
}
dwRt = WaitForSingleObject(g_EventHandle[2][dwii],0);
if (WAIT_OBJECT_0 == dwRt)
{
WriteCBuffer(ldw_ThreadID);
SetEvent(g_EventHandle[2][ldw_ThreadID]);
}
dwRt = WaitForSingleObject(g_EventHandle[3][dwii],0);
if (WAIT_OBJECT_0 == dwRt)
{
WriteDBuffer(ldw_ThreadID);
SetEvent(g_EventHandle[3][ldw_ThreadID]);
}
}
SetEvent(g_ThreadExitHandle[ldw_ThreadID]); //通知主线程,本线程已退出
return 0;
}
int main()
{
int ii = 0,jj = 0,kk = 0;
//初始化临界区
InitializeCriticalSection(&g_Critical);
//创建各部分事件对象及线程
g_ExitThreadHandle = CreateEvent(NULL,TRUE,FALSE,NULL);
for (jj = 0; jj < EVENT_NUM;jj++)
{
for(kk = 0; kk < EVENT_NUM;kk++)
g_EventHandle[jj][kk] = CreateEvent(NULL,FALSE,FALSE,NULL);
}
//按需设置事件对象为信号状态
SetEvent(g_EventHandle[0][3]);
SetEvent(g_EventHandle[1][0]);
SetEvent(g_EventHandle[2][1]);
SetEvent(g_EventHandle[3][2]);
HANDLE lh_ThreadHandle = INVALID_HANDLE_VALUE;
for(ii = 0 ; ii < THREAD_NUM;ii++)
{
lh_ThreadHandle = CreateThread(NULL,0,ThreadFunc,(LPVOID)ii,0,&g_dwThreadID[ii]);
if (NULL != lh_ThreadHandle)
{
//释放主线程对内核对象的引用计数
CloseHandle(lh_ThreadHandle);
}
else
return -1;
g_ThreadExitHandle[ii] = CreateEvent(NULL,FALSE,FALSE,NULL);
}
printf("按下回车查看运行结果");
while(getchar() != '\n');//等待按下回车,退出程序
SetEvent(g_ExitThreadHandle);
//wait thread exit and delete critical section
DWORD dwrt = WaitForMultipleObjects(THREAD_NUM,g_ThreadExitHandle,TRUE,INFINITE);
DeleteCriticalSection(&g_Critical);
//清理内核对象的引用计数
CloseHandle(g_ExitThreadHandle);
g_ExitThreadHandle = INVALID_HANDLE_VALUE;
for (jj = 0; jj < EVENT_NUM;jj++)
{
for(kk = 0; kk < EVENT_NUM;kk++)
{
CloseHandle(g_EventHandle[jj][kk]);
g_EventHandle[jj][kk] = INVALID_HANDLE_VALUE;
}
}
for(ii = 0 ; ii < THREAD_NUM;ii++)
{
CloseHandle(g_ThreadExitHandle[ii]);
g_ThreadExitHandle[ii] = INVALID_HANDLE_VALUE;
}
//输出结果
for (ii = 0;ii < g_ABufTail;ii++)
{
putchar(g_ABuf[ii]);
}
putchar('\n');
for (ii = 0;ii < g_BBufTail;ii++)
{
putchar(g_BBuf[ii]);
}
putchar('\n');
for (ii = 0;ii < g_CBufTail;ii++)
{
putchar(g_CBuf[ii]);
}
putchar('\n');
for (ii = 0;ii < g_DBufTail;ii++)
{
putchar(g_DBuf[ii]);
}
putchar('\n');
printf("按下回车退出");
while(getchar() != '\n');
return 0;
}