C语言多线程编程二

一. 线程通信----事件:

  1.一对一模式:

#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. 一对一中介者模式:

#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. 信号量用作“关卡”的作用:

//信号量-->关卡的作用
#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");
}

三. 互斥锁:

  相关函数如下:

    第一个 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模式下结果为:

        

 

posted @ 2018-08-20 19:42  博观&约取  阅读(1259)  评论(0编辑  收藏  举报