谷歌面试题 多线程的同步与互斥操作

题目来源:秒杀多线程第一篇 多线程笔试面试题汇总
/********************************/
第五题(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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值