• 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.
    ", i);
        Sleep(1000);
        SetEvent(event[1]);
    
        while (++i)
        {
            WaitForSingleObject(event[0], INFINITE);    //无限等待一个信号
            printf("张%d次说:I love you Li.
    ", 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.
    ", 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
    ", i,str);
                Sleep(1000);
                SetEvent(event[2]);
    
                k = 1;
            }
            else
            {
                WaitForSingleObject(event[3], INFINITE);    //无限等待一个信号
                printf("媒婆读取%d次:%s
    ", 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.
    ", i);*/
        memset(str, '0', 256);
        sprintf(str,"张%d次说:I love you Li.
    ", i);
        Sleep(1000);
        SetEvent(event[1]);
    
        while (++i)
        {
            WaitForSingleObject(event[0], INFINITE);    //无限等待一个信号
            /*printf("张%d次说:I love you Li.
    ", i);*/
            memset(str, '0', 256);
            sprintf(str,"张%d次说:I love you Li.
    ", 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.
    ", i);*/
            memset(str, '0', 256);
            sprintf(str,"李%d次说:I love you too.
    ", 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.
    ", *pch);
    
        if (*pch == 'A')
        {
            MessageBoxA(0, "1", "1", 0);
            sprintf(str,"张女友-%c speak: xiaohaha 
    ", *pch);
            SetEvent(event[0]);
        }
    
        int i = 0;
        while (++i)
        {
            WaitForSingleObject(event[0], INFINITE);
            printf("ZhangGirlFriend-%c read %s
    ", *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...
    ", *pint);
    
        HANDLE myhsem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, id);    //打开一个信号
        if (myhsem)
        {
            printf("myworker%d is waiting...
    ", *pint);
            //初始时信号为0,为0就会死锁,信号量不减
            //不为0的情况下,信号量-1
            if (WaitForSingleObject(myhsem, INFINITE) == WAIT_OBJECT_0)    //等到了信号
            {
                printf("myworker%d is getting.
    ", *pint);
                Sleep(3000);
    
                printf("myworker%d is leaving.
    ", *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("激活线程.
    ");
        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("信号量获取失败.
    ");
        }
    
        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("激活线程.
    ");
        ReleaseSemaphore(hSEM, 1, NULL);    //一次放过一个
    
        WaitForMultipleObjects(64, hd, TRUE, INFINITE);
    
        printf("%d
    ", 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
    ", i, num);
    
            if (i == 10)
            {
                break;
            }
    
            i++;
        }
    
        ReleaseSRWLockShared(&g_lock);
    
        return 1;
    }
    
    
    //改变一个变量的时候需要锁定
    DWORD WINAPI write(void *p)
    {
        AcquireSRWLockExclusive(&g_lock);    //锁定写入
        printf("开始写入...
    ");
        for (int i = 0; i < 100000; i++)
        {
            num--;
            //Sleep(10);
        }
        ReleaseSRWLockExclusive(&g_lock);
        printf("结束写入...
    ");
        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
    ", 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("打开失败!
    ");
            system("pause");
            return;
        }
        printf("等待------
    ");
    
        DWORD res = WaitForSingleObject(mutex, 10000);
        switch (res)
        {
        case WAIT_OBJECT_0:
            printf("收到信号---
    ");
            break;
        case WAIT_TIMEOUT:
            printf("超时没有收到---
    ");
            break;
        case WAIT_ABANDONED:
            printf("另外一个进程意外终止---
    ");
            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("创建成功!
    ");
        char ch = getchar();
    
        ReleaseMutex(mutex);        //离开互斥区
        printf("触发互斥量.
    ");
        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("创建成功!
    ");
        char ch = getchar();
    
        SetEvent(event);
        printf("触发event.
    ");
        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("打开失败!
    ");
            system("pause");
            return;
        }
        printf("等待------
    ");
    
        DWORD res = WaitForSingleObject(event, 10000);
        switch (res)
        {
        case WAIT_OBJECT_0:
            printf("收到信号---
    ");
            break;
        case WAIT_TIMEOUT:
            printf("超时没有收到---
    ");
            break;
        case WAIT_ABANDONED:
            printf("另外一个进程意外终止---
    ");
            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("创建成功!
    ");
        char ch = getchar();
    
        ReleaseSemaphore(hsem, 1, NULL);
        printf("触发信号量semaphore.
    ");
        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("打开失败!
    ");
            system("pause");
            return;
        }
        printf("等待------
    ");
    
        DWORD res = WaitForSingleObject(hsem, 10000);
        switch (res)
        {
        case WAIT_OBJECT_0:
            printf("收到信号---
    ");
            break;
        case WAIT_TIMEOUT:
            printf("超时没有收到---
    ");
            break;
        case WAIT_ABANDONED:
            printf("另外一个进程意外终止---
    ");
            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次
    ", dwindex);
    }
    
    void main()
    {
        HANDLE timer1 = CreateWaitableTimerA(NULL, TRUE, "hello");//创建时钟
        if (timer1 == NULL)
        {
            printf("创建失败!
    ");
        }
    
        LARGE_INTEGER mytime;
        mytime.QuadPart = -50000000;    //单位是0.1微秒
    
        DWORD dwparam = 1;    //设置定时器
    
        if (SetWaitableTimer(timer1, &mytime, 1000, timerun, &dwparam, FALSE))//1000 1秒循环一次
        {
            printf("等待5秒后开始干活!
    ");
            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
    ", a);
    
        //偷偷改变i
        __asm
        {
            mov dword ptr[ebp-4],20h    //16进制 20h=32
        }
    
        int b = i;
        printf("i=%d
    ", b);
    
        system("pause");
    }

      上面结果在Debug模式下结果为:

            

      在Release模式下结果为:

            

  • 相关阅读:
    [C#.net]获取文本文件的编码,自动区分GB2312和UTF8
    [C#.net]SqlDataAdapter 执行超时已过期 完成操作之前已超时或服务器未响应
    [C#.Net]Window服务调用外部程序
    [Bat]UNC路径不支持的2种解决方法
    [c#.net]未能加载文件或程序集“”或它的某一个依赖项。系统找不到指定的文件
    精读比特币论文
    动态添加Redis密码认证
    扫码登录的安全性分析
    Cookie与Passport安全
    Http压测工具wrk使用指南
  • 原文地址:https://www.cnblogs.com/si-lei/p/9506292.html
Copyright © 2020-2023  润新知