c++多线程实现循环打印ABC

时间:2021-01-03 18:35:04

网上的资料基本都是java实现的,c++的很少,加上win32的API函数对我个人而言晦涩难懂,真是举步维艰~

目前而言对我来说最好理解的,最简单的,是使用Event。
首先明白Event的用法:秒杀多线程第六篇 经典线程同步 事件Event

CreateEvent

函数功能:创建事件

//函数原型:

HANDLECreateEvent( LPSECURITY_ATTRIBUTESlpEventAttributes, BOOLbManualReset, BOOLbInitialState, LPCTSTRlpName );

函数说明:

  • 第一个参数表示安全控制,一般直接传入NULL。
  • 第二个参数确定事件是手动置位还是自动置位,传入TRUE表示手动置位,传入FALSE表示自动置位。如果为自动置位,则对该事件调用WaitForSingleObject()后会自动调用ResetEvent()使事件变成未触发状态。打个小小比方,手动置位事件相当于教室门,教室门一旦打开(被触发),所以有人都可以进入直到老师去关上教室门(事件变成未触发)。自动置位事件就相当于医院里拍X光的房间门,门打开后只能进入一个人,这个人进去后会将门关上,其它人不能进入除非门重新被打开(事件重新被触发)。
    (此中有坑)
  • 第三个参数表示事件的初始状态,传入TRUR表示已触发。
  • 第四个参数表示事件的名称,传入NULL表示匿名事件。

SetEvent

函数功能:触发事件
函数原型:BOOLSetEvent(HANDLEhEvent);
函数说明:每次触发后,必有一个或多个处于等待状态下的线程变成可调度状态。

ResetEvent

函数功能:将事件设为末触发

函数原型:BOOLResetEvent(HANDLEhEvent);

最简单的实现是,先分别创建三个线程分别打印对应次数的字母A/B/C,还有三个事件event ,其中每个线程在打印的时候使用waitforsingleobject来阻塞,只有wait到了对应的事件,才可以输出对应的字母,然后打印完毕后,用setevent把下一个事件触发,然后执行下一个事件。

最简单的代码:

using namespace std;
const int NUM = 3;
int nCount = 1;  //用来表示先打印哪一个 0-A,1-B,2-C
HANDLE g_Event[NUM] = { NULL };//三个事件

unsigned int WINAPI funA(LPVOID pM)
{
    for (int i = 0; i < 100; i++)
    {

        WaitForSingleObject(g_Event[0], INFINITE);   //等待g_Event[0],然后才执行打印A;
        cout << 'A';
        Sleep(100);
        nCount ++ ;
        SetEvent(g_Event[(nCount) % NUM]);
    }
    return 0;
}
unsigned int WINAPI funB(LPVOID pM)
{

    for (int i = 0; i < 100; i++)
    {

        WaitForSingleObject(g_Event[1], INFINITE);
        cout << 'B';
        Sleep(100);
        nCount++;
        SetEvent(g_Event[(nCount) % NUM]);
    }
    return 0;
}
unsigned int WINAPI funC(LPVOID pM)
{
    for (int i = 0; i < 100; i++)
    {

        WaitForSingleObject(g_Event[2], INFINITE);
        cout << 'C';
        Sleep(100);
        nCount++;
        SetEvent(g_Event[(nCount) % NUM]);
    }
    return 0;
}
int main()
{

    HANDLE threads[NUM] = { NULL };

    for (unsigned int i = 0; i < 3; i++)
    {
        g_Event[i] = CreateEvent(NULL, FALSE, FALSE, NULL);  //这里的第二个参数是False,意思是这个事件执行完后,会自动设置为未触发状态(形参3的参数就是设置默认是否为触发),如果是TRUE,则需要执行完后手动置为未触发,用ResetEvent函数即可。

    }
    threads[0] = (HANDLE)_beginthreadex(NULL, 0, funA, NULL, 0, NULL);
    threads[1] = (HANDLE)_beginthreadex(NULL, 0, funB, NULL, 0, NULL);
    threads[2] = (HANDLE)_beginthreadex(NULL, 0, funC, NULL, 0, NULL);
    SetEvent(g_Event[nCount]);
    WaitForMultipleObjects(NUM, threads, TRUE, INFINITE);

    CloseHandle(g_Event[0]);
    CloseHandle(g_Event[1]);
    CloseHandle(g_Event[2]);
    memset(g_Event, 0, sizeof(HANDLE)*NUM);
    CloseHandle(threads[0]);
    CloseHandle(threads[1]);
    CloseHandle(threads[2]);
    memset(threads, 0, sizeof(HANDLE)*NUM);


    return 0;
}

写的太复杂了,还用了EVENT数组,简直是没有困难创造困难。
下面的这个代码就很好理解。
http://blog.csdn.net/bupt8846/article/details/45541723

#include <stdio.h> 
#include <windows.h> 
#include<iostream> 
#include <process.h> 
#include <time.h> 
using namespace std;  

HANDLE g_a, g_b, g_c;  
CRITICAL_SECTION g_cs;  

unsigned int __stdcall PrintA(void* pM)  
{  
    int i = 0;  
    while (i < 10)  
    {  
        WaitForSingleObject(g_a, INFINITE);  
        //EnterCriticalSection(&g_cs); 
        cout <<i+1<< ": A";  
        ++i;  
        SetEvent(g_b);  

        //LeaveCriticalSection(&g_cs); 
    }  
    return 0;  
}  

unsigned int __stdcall PrintB(void* pM)  
{  
    int i = 0;  
    while (i < 10)  
    {  
        WaitForSingleObject(g_b, INFINITE);  
        //EnterCriticalSection(&g_cs); 
        cout << 'B';  
        ++i;  
        SetEvent(g_c);  

        //LeaveCriticalSection(&g_cs); 
    }  
    return 0;  
}  

unsigned int __stdcall PrintC(void* pM)  
{  
    int i = 0;  
    while (i < 10)  
    {  
        WaitForSingleObject(g_c, INFINITE);  
        //EnterCriticalSection(&g_cs); 
        cout << "C\n";  
        ++i;  
        SetEvent(g_a);  

        //LeaveCriticalSection(&g_cs); 
    }  
    return 0;  
}  

int _tmain(int argc, _TCHAR* argv[])  
{  
    InitializeCriticalSection(&g_cs);  
    g_a = CreateEvent(NULL, FALSE, TRUE, NULL);   //这里设置为TRUE,默认g_a是触发的。
    g_b = CreateEvent(NULL, FALSE, FALSE, NULL);  
    g_c = CreateEvent(NULL, FALSE, FALSE, NULL);  
    HANDLE threads[3];  

    threads[0] = (HANDLE)_beginthreadex(NULL, 0, PrintA, NULL, 0, NULL);  
    threads[1] = (HANDLE)_beginthreadex(NULL, 0, PrintB, NULL, 0, NULL);  
    threads[2] = (HANDLE)_beginthreadex(NULL, 0, PrintC, NULL, 0, NULL);  

    WaitForMultipleObjects(3, threads, TRUE, INFINITE);  

    CloseHandle(g_a);  
    CloseHandle(g_b);  
    CloseHandle(g_c);  
    CloseHandle(threads[0]);  
    CloseHandle(threads[1]);  
    CloseHandle(threads[2]);  
    DeleteCriticalSection(&g_cs);  


    cout << endl;  
    system("pause");  
    return 0;  
}  

简单的版本,避免代码重复太多。

using namespace std;
const int NUM = 3;
int nCount = 1;
HANDLE g_Event[NUM] = { NULL };
//HANDLE g_Mutex = NULL ;

unsigned int WINAPI fun(LPVOID pM)
{
    int nParam = (int)pM;          
    char res = 'A' + nParam;
    for (int i = 0; i < 100; i++)
    {

        WaitForSingleObject(g_Event[nParam], INFINITE);
        cout << res;
        Sleep(100);
        ResetEvent(g_Event[nParam]);
        SetEvent(g_Event[(nParam + 1) % NUM]);  //触发下一个事件
    }
    return 0;
}
int main()
{

    HANDLE threads[NUM] = { NULL };

    for (unsigned int i = 0; i < 3; i++)
    {
        g_Event[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
        threads[i] = (HANDLE)_beginthreadex(NULL, 0, fun, (void *)i, 0, NULL);
    }

    SetEvent(g_Event[nCount]);
    WaitForMultipleObjects(NUM, threads, TRUE, INFINITE);

    CloseHandle(g_Event[0]);
    CloseHandle(g_Event[1]);
    CloseHandle(g_Event[2]);
    memset(g_Event, 0, sizeof(HANDLE)*NUM);
    CloseHandle(threads[0]);
    CloseHandle(threads[1]);
    CloseHandle(threads[2]);
    memset(threads, 0, sizeof(HANDLE)*NUM);


    return 0;
}