MoreNotepad++

--------活出自己的精彩。

导航

Google的多线程面试题

题目如下: 
    启动4个线程,向4个文件A,B,C,D里写入数据,每个线程只能写一个值。 
    线程1:只写1 
    线程2:只写2 
    线程3:只写3 
    线程4:只写4 
    4个文件A,B,C,D。 
    程序运行起来,4个文件的写入结果如下: 
    A:12341234... 
    B:23412341... 
    C:34123412... 
    D:41234123...

初次遇见这个题目的时候真是一头雾水,思维完全陷入了各种各样的锁操作中。最近在学习设计模式的时候(责任链模式),突发灵感。完全可以用这个模式的思想来解决这个问题,相当简单,一个锁都不需要。

比如我是线程A,我要做的事情很简单,就是往文件里面输出一个字符'1',然后通知线程2也去这个文件里面去输出他该输出的字符。现在责任很明确,唯一的问题就是该具体到哪个文件。把文件比喻成接力棒,当你收到这个接力棒的时候,输出字符,然后把接力棒传递给下一个人。其他3个线程也按照这个模式执行的话,那么整个责任链就形成了。然后每个线程该输出什么,该通知谁,我们可以在创建线程的时候就可以预先指定好。准备好以后,我们就可以将4个接力棒分给这几个线程。

#include <stdio.h>
#include <process.h>
#include <windows.h>
#include <fstream>
#include <string.h>

using namespace std;

fstream file1;
fstream file2;
fstream file3;
fstream file4;

HANDLE handles[4];
DWORD  threadID[4];

#define WM_MY_NOTIFY (WM_USER + 1)

DWORD WINAPI ThreadProc(LPVOID lpParameter);

struct Task
{
    string _text;// i know which text the thread need to print
    fstream* _fp; //i don't know which file the thread need to print (Compilation phase)(no useful)
    DWORD* _pThreadID2Notity;// i also know which thread should i need to notify

    void runTask(fstream *fp) { // i know how to run my task
        (*fp) << _text;
        PostThreadMessage(*_pThreadID2Notity, WM_MY_NOTIFY, (WPARAM)fp, 0);
    }
};

int main()
{
    file1.open("1.txt", fstream::out | fstream::trunc);
    file2.open("2.txt", fstream::out | fstream::trunc);
    file3.open("3.txt", fstream::out | fstream::trunc);
    file4.open("4.txt", fstream::out | fstream::trunc);
    
    Task task[] = { {"1 ", NULL, threadID + 1},
                    {"2 ", NULL, threadID + 2},
                    {"3 ", NULL, threadID + 3},
                    {"4\n",NULL, threadID + 0}};

    for (int i = 0; i < 4; i++)
    {
        handles[i] = CreateThread(NULL, // default security attributes
                                  0, // use default stack size
                                  ThreadProc, // thread function
                                  (LPVOID)(task + i), // the task
                                  0, // run right now
                                  threadID + i); // returns the thread identifier
    }
    
    Sleep(1000); //the thread need some times to build message queue.

    PostThreadMessage(threadID[0], WM_MY_NOTIFY, WPARAM(&file1), 0); //send baton 1
    PostThreadMessage(threadID[1], WM_MY_NOTIFY, WPARAM(&file2), 0); //send baton 2
    PostThreadMessage(threadID[2], WM_MY_NOTIFY, WPARAM(&file3), 0); //send baton 3
    PostThreadMessage(threadID[3], WM_MY_NOTIFY, WPARAM(&file4), 0); //send baton 4

    Sleep(5 * 1000);

    for (int i = 0; i < 4; i++)
    {
        PostThreadMessage(threadID[i], WM_QUIT, 0, 0);
    }
    
    WaitForMultipleObjects(4, handles, true, INFINITE);

    file1.close();
    file2.close();
    file3.close();
    file4.close();
    
    for (int i = 0; i < 4; i++)
    {
        CloseHandle(handles[i]);
    }

    return 0;
}

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    Task *pTask = (Task*)lpParameter;
    
    MSG msg;

    fstream *pfile = NULL;

    while(GetMessage(&msg, NULL, 0, 0) != 0)
    {
        if (msg.message == WM_MY_NOTIFY)
        {
            pfile = (fstream*)msg.wParam; // get my baton

            pTask->runTask(pfile);
        }
        
        Sleep(100);
    }

    return 1;
}

 

posted on 2013-06-20 17:46  MoreNotepad++  阅读(455)  评论(0)    收藏  举报