C語言多線程編程二

一. 線程通訊----事件:函數

  1.一對一模式:ui

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

//互斥解決線程衝突
//事件解決線程通訊
//臨界區解決線程衝突
//時間同步線程

HANDLE event[5] = { 0 };
HANDLE hd[5] = { 0 };

DWORD WINAPI Zhang(void *p)
{
    int i = 1;
    printf("張%d次說:I love you Li.\n", i);
    Sleep(1000);
    SetEvent(event[1]);

    while (++i)
    {
        WaitForSingleObject(event[0], INFINITE);    //無限等待一個信號
        printf("張%d次說:I love you Li.\n", i);
        Sleep(1000);
        //ResetEvent(event[0]);    //信號復位
        SetEvent(event[1]);
    }

    return 0;
}
DWORD WINAPI Li(void *p)
{
    int i = 0;
    while (++i)
    {
        WaitForSingleObject(event[1], INFINITE);    //無限等待一個信號
        printf("李%d次說:I love you too.\n", i);
        Sleep(1000);
        //ResetEvent(event[1]);    //信號復位
        SetEvent(event[0]);
    }

    return 0;
}

void main()
{
    //第二個參數表明:自動FALSE、手動TRUE(須要reset)
    //第三個參數信號狀態
    //第四個參數標記名稱
    //event[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
    //event[1] = CreateEvent(NULL, TRUE, FALSE, NULL);

    event[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
    event[1] = CreateEvent(NULL, FALSE, FALSE, NULL);

    hd[0] = CreateThread(NULL, 0, Zhang, NULL, 0, NULL);
    hd[1] = CreateThread(NULL, 0, Li, NULL, 0, NULL);

    WaitForMultipleObjects(2, hd, TRUE, INFINITE);

    system("pause");
}

   2. 一對一中介者模式:spa

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

//互斥解決線程衝突
//事件解決線程通訊
//臨界區解決線程衝突
//時間同步線程

HANDLE event[5] = { 0 };
HANDLE hd[5] = { 0 };

char str[256] = { 0 };    //全局變量,存放說的內容

DWORD WINAPI Wang(void *p)
{
    int i = 0;
    int k = 0;    //判斷是哪一個信號

    while (++i)
    {
        if (k == 0)
        {
            WaitForSingleObject(event[1], INFINITE);    //無限等待一個信號
            printf("媒婆讀取%d次:%s\n", i,str);
            Sleep(1000);
            SetEvent(event[2]);

            k = 1;
        }
        else
        {
            WaitForSingleObject(event[3], INFINITE);    //無限等待一個信號
            printf("媒婆讀取%d次:%s\n", i, str);
            Sleep(1000);
            SetEvent(event[0]);

            k = 0;
        }

    }

    return 0;
}

DWORD WINAPI Zhang(void *p)
{
    int i = 1;
    /*printf("張%d次說:I love you Li.\n", i);*/
    memset(str, '0', 256);
    sprintf(str,"張%d次說:I love you Li.\n", i);
    Sleep(1000);
    SetEvent(event[1]);

    while (++i)
    {
        WaitForSingleObject(event[0], INFINITE);    //無限等待一個信號
        /*printf("張%d次說:I love you Li.\n", i);*/
        memset(str, '0', 256);
        sprintf(str,"張%d次說:I love you Li.\n", i);
        Sleep(1000);
        //ResetEvent(event[0]);    //信號復位
        SetEvent(event[1]);
    }

    return 0;
}
DWORD WINAPI Li(void *p)
{
    int i = 0;
    while (++i)
    {
        WaitForSingleObject(event[2], INFINITE);    //無限等待一個信號
        /*printf("李%d次說:I love you too.\n", i);*/
        memset(str, '0', 256);
        sprintf(str,"李%d次說:I love you too.\n", i);
        Sleep(1000);
        //ResetEvent(event[1]);    //信號復位
        SetEvent(event[3]);
    }

    return 0;
}

void main()
{
    //第二個參數表明:自動FALSE、手動TRUE(須要reset)
    //第三個參數信號狀態
    //第四個參數標記名稱
    //event[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
    //event[1] = CreateEvent(NULL, TRUE, FALSE, NULL);

    event[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
    event[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
    event[2] = CreateEvent(NULL, FALSE, FALSE, NULL);
    event[3] = CreateEvent(NULL, FALSE, FALSE, NULL);

    hd[0] = CreateThread(NULL, 0, Zhang, NULL, 0, NULL);
    hd[1] = CreateThread(NULL, 0, Li, NULL, 0, NULL);
    hd[2] = CreateThread(NULL, 0, Wang, NULL, 0, NULL);

    WaitForMultipleObjects(3, hd, TRUE, INFINITE);

    system("pause");
}

  3. 一對多廣播模式:線程

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

//互斥解決線程衝突
//事件解決線程通訊
//臨界區解決線程衝突
//時間同步線程
HANDLE event[5] = { 0 };
HANDLE hd[10] = { 0 };

char ch[10] = { 'A','B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' };
char str[256] = { 0 };

DWORD WINAPI ZhangGirlFriend(void *p)
{
    char *pch = p;
    printf("I am %c ZhangGirlFrend.\n", *pch);

    if (*pch == 'A')
    {
        MessageBoxA(0, "1", "1", 0);
        sprintf(str,"張女朋友-%c speak: xiaohaha \n", *pch);
        SetEvent(event[0]);
    }

    int i = 0;
    while (++i)
    {
        WaitForSingleObject(event[0], INFINITE);
        printf("ZhangGirlFriend-%c read %s\n", *pch, str);
        Sleep(1000);
        ResetEvent(event[0]);
    }

    return 0;
}

void main()
{
    //第二個參數表明:自動FALSE(收到一次自動清空一次)、手動TRUE(須要reset)
    //第三個參數信號狀態
    //第四個參數標記名稱
    event[0] = CreateEventA(NULL, TRUE, FALSE, "msg");    //一直等待消息

    for (int i = 0; i < 10; i++)
    {
        hd[i] = CreateThread(NULL, 0, ZhangGirlFriend, &ch[i], 0, NULL);
    }

    WaitForMultipleObjects(10, hd, TRUE, INFINITE);

    system("pause");
}

二. 信號量:指針

  1. 信號量用做「關卡」的做用:code

//信號量-->關卡的做用
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

#define id "Zhang"
#define MAX 3

//0 無限等待
DWORD WINAPI myworker(void *p)
{
    int *pint = p;
    printf("myworker%d is running...\n", *pint);

    HANDLE myhsem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, id);    //打開一個信號
    if (myhsem)
    {
        printf("myworker%d is waiting...\n", *pint);
        //初始時信號爲0,爲0就會死鎖,信號量不減
        //不爲0的狀況下,信號量-1
        if (WaitForSingleObject(myhsem, INFINITE) == WAIT_OBJECT_0)    //等到了信號
        {
            printf("myworker%d is getting.\n", *pint);
            Sleep(3000);

            printf("myworker%d is leaving.\n", *pint);
            ReleaseSemaphore(myhsem, 1, NULL);//釋放資源 +1
            CloseHandle(myhsem);//執行完成退出
        }
    }

    return 1;
}

void main()
{
    //建立信號對象
    HANDLE hSEM = CreateSemaphore(NULL, 0, MAX, id);//開闢一個信號,最大計數是3


    int a[10] = { 0,1,2,3,4,5,6,7,8,9 };

    HANDLE hd[10] = { 0 };
    for (int i = 0; i < 10; i++)
    {
        hd[i] = CreateThread(NULL, 0, myworker, a + i, 0, NULL);    //建立10個線程
    }
    Sleep(5000);


    printf("激活線程.\n");
    ReleaseSemaphore(hSEM, MAX, NULL);//最多一次放過3個 +3

    WaitForMultipleObjects(10, hd, TRUE, INFINITE);

    CloseHandle(hSEM);

    system("pause");
}

  2. 信號量實現互斥:對象

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

int num = 0;

//互斥量,只能讓一個線程運行,其餘休眠
//信號量,能夠讓多個線程運行,其餘線程休眠
//臨界區,只能讓一個線程運行,其餘休眠
//原子操做,操做速度最快
//事件也能夠實現互斥
DWORD WINAPI add(void *p)
{
    HANDLE myhsem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Hello");    
    if (myhsem)
    {

        if (WaitForSingleObject(myhsem, INFINITE) == WAIT_OBJECT_0)    //等到了信號
        {
            for (int i = 0; i < 10000; i++)
            {
                num++;
            }

            ReleaseSemaphore(myhsem, 1, NULL);//釋放資源 +1
            CloseHandle(myhsem);//執行完成退出
        }
    }
    else
    {
        printf("信號量獲取失敗.\n");
    }

    return 1;
}

void main()
{
    HANDLE hSEM = CreateSemaphore(NULL, 0, 1, "Hello");

    HANDLE hd[64] = { 0 };
    for (int i = 0; i < 64; i++)
    {
        hd[i] = CreateThread(NULL, 0, add, NULL, 0, NULL);    //建立64個線程
    }
    Sleep(2000);

    printf("激活線程.\n");
    ReleaseSemaphore(hSEM, 1, NULL);    //一次放過一個

    WaitForMultipleObjects(64, hd, TRUE, INFINITE);

    printf("%d\n", num);

    CloseHandle(hSEM);

    system("pause");
}

三. 互斥鎖:blog

  相關函數以下:進程

    第一個 InitializeSRWLock
    函數功能:初始化讀寫鎖
    函數原型:VOID InitializeSRWLock(PSRWLOCK SRWLock);
    函數說明:初始化(沒有刪除或銷燬SRWLOCK的函數,系統會自動清理)事件


    第二個 AcquireSRWLockExclusive
    函數功能:寫入者線程申請寫資源。
    函數原型:VOID AcquireSRWLockExclusive(PSRWLOCK SRWLock);

 

    第三個 ReleaseSRWLockExclusive
    函數功能:寫入者線程寫資源完畢,釋放對資源的佔用。
    函數原型:VOID ReleaseSRWLockExclusive(PSRWLOCK SRWLock);

    第四個 AcquireSRWLockShared
    函數功能:讀取者線程申請讀資源。
    函數原型:VOID AcquireSRWLockShared(PSRWLOCK SRWLock);

    第五個 ReleaseSRWLockShared
    函數功能:讀取者線程結束讀取資源,釋放對資源的佔用。
    函數原型:VOID ReleaseSRWLockShared(PSRWLOCK SRWLock);

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

int num = 6400000;
SRWLOCK g_lock;    

//注意一個線程僅能鎖定資源一次,不能屢次鎖定資源。
DWORD WINAPI read(void *p)
{
    AcquireSRWLockShared(&g_lock);    //讀取期間鎖定數據,數據沒法被修改

    int i = 0;
    while (1)
    {
        Sleep(1000);
        printf("第%d秒num=%d\n", i, num);

        if (i == 10)
        {
            break;
        }

        i++;
    }

    ReleaseSRWLockShared(&g_lock);

    return 1;
}


//改變一個變量的時候須要鎖定
DWORD WINAPI write(void *p)
{
    AcquireSRWLockExclusive(&g_lock);    //鎖定寫入
    printf("開始寫入...\n");
    for (int i = 0; i < 100000; i++)
    {
        num--;
        //Sleep(10);
    }
    ReleaseSRWLockExclusive(&g_lock);
    printf("結束寫入...\n");
    return 1;
}

void main()
{
    InitializeSRWLock(&g_lock);    //初始化互斥鎖

    CreateThread(NULL, 0, read, NULL, 0, NULL);

    HANDLE hd[64];
    for (int i = 0; i < 64; i++)
    {
        hd[i] = CreateThread(NULL, 0, write, NULL, 0, NULL);
    }
    WaitForMultipleObjects(64, hd, TRUE, INFINITE);

    printf("last=%d\n", num);

    system("pause");
}

 四. 跨進程通訊:

1. 信號量mutex 跨進程通訊:

  文件mutex1.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

char name[100] = "Zhang love Li";

void main()
{
    HANDLE mutex = OpenMutexA(MUTEX_ALL_ACCESS, TRUE, name);
    if (mutex == NULL)
    {
        printf("打開失敗!\n");
        system("pause");
        return;
    }
    printf("等待------\n");

    DWORD res = WaitForSingleObject(mutex, 10000);
    switch (res)
    {
    case WAIT_OBJECT_0:
        printf("收到信號---\n");
        break;
    case WAIT_TIMEOUT:
        printf("超時沒有收到---\n");
        break;
    case WAIT_ABANDONED:
        printf("另一個進程意外終止---\n");
        break;
    default:
        break;
    }

    CloseHandle(mutex);
    system("pause");
}

  文件mutex2.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

char name[100] = "Zhang love Li";

void main()
{
    HANDLE mutex = CreateMutexA(NULL, TRUE, name);
    printf("建立成功!\n");
    char ch = getchar();

    ReleaseMutex(mutex);        //離開互斥區
    printf("觸發互斥量.\n");
    CloseHandle(mutex);

    system("pause");
}

  運行結果:

 2. 事件 event 跨進程通訊:

  文件event.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

char name[100] = "Zhang love Li";

//只有mutex能夠感知丟失,event沒法感知
void main()
{
    HANDLE event = CreateEventA(NULL, FALSE, FALSE, name);
    printf("建立成功!\n");
    char ch = getchar();

    SetEvent(event);
    printf("觸發event.\n");
    CloseHandle(event);

    system("pause");
}

  文件 wait.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

char name[100] = "Zhang love Li";

void main()
{
    HANDLE event = OpenEventA(EVENT_ALL_ACCESS, TRUE, name);//打開事件
    if (event == NULL)
    {
        printf("打開失敗!\n");
        system("pause");
        return;
    }
    printf("等待------\n");

    DWORD res = WaitForSingleObject(event, 10000);
    switch (res)
    {
    case WAIT_OBJECT_0:
        printf("收到信號---\n");
        break;
    case WAIT_TIMEOUT:
        printf("超時沒有收到---\n");
        break;
    case WAIT_ABANDONED:
        printf("另一個進程意外終止---\n");
        break;
    default:
        break;
    }

    CloseHandle(event);
    system("pause");
}

 3. 信號 semaphore 跨進程通訊:

  semaphore.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

char name[100] = "Zhang love Li";

//只有mutex能夠感知丟失,event沒法感知
void main()
{
    HANDLE hsem = CreateSemaphoreA(NULL, 0, 1, name);
    printf("建立成功!\n");
    char ch = getchar();

    ReleaseSemaphore(hsem, 1, NULL);
    printf("觸發信號量semaphore.\n");
    CloseHandle(hsem);

    system("pause");
}

  wait.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

char name[100] = "Zhang love Li";

void main()
{
    HANDLE hsem = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, TRUE, name);
    if (hsem == NULL)
    {
        printf("打開失敗!\n");
        system("pause");
        return;
    }
    printf("等待------\n");

    DWORD res = WaitForSingleObject(hsem, 10000);
    switch (res)
    {
    case WAIT_OBJECT_0:
        printf("收到信號---\n");
        break;
    case WAIT_TIMEOUT:
        printf("超時沒有收到---\n");
        break;
    case WAIT_ABANDONED:
        printf("另一個進程意外終止---\n");
        break;
    default:
        break;
    }

    CloseHandle(hsem);
    system("pause");
}

 五. 回調函數與定時器:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

//回調函數,函數指針能夠來調用
VOID CALLBACK timerun(void *parg, DWORD timearg, DWORD timehigh)
{
    DWORD dwindex = *(DWORD *)parg;
    printf("第%d次\n", dwindex);
}

void main()
{
    HANDLE timer1 = CreateWaitableTimerA(NULL, TRUE, "hello");//建立時鐘
    if (timer1 == NULL)
    {
        printf("建立失敗!\n");
    }

    LARGE_INTEGER mytime;
    mytime.QuadPart = -50000000;    //單位是0.1微秒

    DWORD dwparam = 1;    //設置定時器

    if (SetWaitableTimer(timer1, &mytime, 1000, timerun, &dwparam, FALSE))//1000 1秒循環一次
    {
        printf("等待5秒後開始幹活!\n");
        for (int i = 0; i < 15; i++, dwparam++)    //循環調用多少次
        {
            SleepEx(INFINITE, TRUE);
        }
    }

    CancelWaitableTimer(timer1);//取消定時器
    CloseHandle(timer1);

    system("pause");
}

六. 原子操做:

#include <stdio.h>
#include <stdlib.h>

void main()
{
    volatile int i = 10;    //數據被意外改變的時候,強制讀內存
    int a = i;
    printf("i=%d\n", a);

    //偷偷改變i
    __asm
    {
        mov dword ptr[ebp-4],20h    //16進制 20h=32
    }

    int b = i;
    printf("i=%d\n", b);

    system("pause");
}

  上面結果在Debug模式下結果爲:

        

  在Release模式下結果爲:

        

相關文章
相關標籤/搜索