• 2022-11-11 C++并发编程( 四十一 )



    前言

    多线程测试较单线程测试难一些, 需要制造一个多线程并发同步环境, 多次测试, 因为并发的乱序, 很多结果是随机的, 需要足够多的次数.

    本文实现一个简单的并发测试结构, 用于测试并发代码.


    一、测试空队列同时 pop, push

    测试并发代码, 需要一个并发环境, 下面的实现是用 async 和 future 保证在多线程上进行, 用 promise 和 future 保证同步, 通过断言进行检查结果.

    一个空队列, 同时进行 pop 和 push 有两种结果,

    第一, push 在先, pop 在后, 没有问题, 断言通过

    第二, pop 在先, push 在后, 则 pop 只能失败, 而后队列 push 成功, 含有一个元素, 断言失败.

    以下实现的结构代码简单, 可扩展到更多线程的同步.

    #include "ThreadSafeQueue_2.h"
    #include 
    #include 
    #include 
    #include 
    
    // 测试并发空队列 push 和 pop
    void testConcurrentPushAndPopOnEmptyQueue()
    {
        // 新建队列
        TS::threadSafeQueue<int> queue;
    
        // 为同步阻塞准备的 promise
        std::promise<void> go;
        std::promise<void> pushReady;
        std::promise<void> popReady;
    
        // 用于同步的 future
        std::shared_future<void> const ready(go.get_future());
    
        // 获取结果的 future
        std::future<void> pushDone;
        std::future<std::shared_ptr<int>> popDone;
    
        try
        {
            // 通过 async 封装测试函数 push
            pushDone =
                std::async(std::launch::async, [&queue, ready, &pushReady]() {
                    // 设置值用于解除 push 阻塞
                    pushReady.set_value();
                    // 阻塞用于同步
                    ready.wait();
                    // 测试 push
                    queue.push(42);
                });
    
            // 通过 async 封装测试函数 pop
            popDone = std::async(std::launch::async, [&queue, ready, &popReady]() {
                // 设置值用于解除 pop 阻塞
                popReady.set_value();
                // 阻塞用于同步
                ready.wait();
    
                // const int result = *queue.tryPop();
    
                // 测试 trypop
                return queue.tryPop();
            });
    
            // 阻塞等待
            pushReady.get_future().wait();
            popReady.get_future().wait();
    
            // 解除阻塞, 开启同步
            go.set_value();
    
            // 返回结果
            pushDone.get();
    
            // 断言结果
            assert(queue.empty());
            assert(*popDone.get() == 42);
        }
        // 捕捉异常
        catch (...)
        {
            go.set_value();
            throw;
        }
    }
    
    auto main() -> int
    {
        // 开始测试
        testConcurrentPushAndPopOnEmptyQueue();
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    总结

    多线程测试由于存在不确定顺序, 通常结果是多样的, 需要多次测试.

    C++ 标准库可以很容易的通过 promise 和 future 达成同步, 同时利用 async 实现多线程, 析构对 future 进行线程汇入, 不必担心线程安全问题.

  • 相关阅读:
    基于springboot+vue的疫情期间外出务工人员信息管理系统
    Flutter实战-自定义键盘(三)
    2023-09-13力扣每日一题
    设计模式——命令模式(Command Pattern)+ Spring相关源码
    Idea Module “xx“ must not contain source root “xxx“ 的解决
    B. Good Kid
    redis 学习记录
    linux mount命令加速
    基于排序变换混沌置乱算法的图像加密系统
    alertmanager 基于webhook-adapter插件实现企业微信机器人提醒服务
  • 原文地址:https://blog.csdn.net/m0_54206076/article/details/127803783