Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C+中测试条件变量+;? 我有一个非常好的基本方法,它调用了一个条件变量(< C++ > > >条件>变量>代码> void WaitForEvent(){ std::唯一锁(互斥锁); 而(!事件计数器){ 条件变量等待(锁定); } 返回; }_C++_Multithreading_Testing - Fatal编程技术网

如何在C+中测试条件变量+;? 我有一个非常好的基本方法,它调用了一个条件变量(< C++ > > >条件>变量>代码> void WaitForEvent(){ std::唯一锁(互斥锁); 而(!事件计数器){ 条件变量等待(锁定); } 返回; }

如何在C+中测试条件变量+;? 我有一个非常好的基本方法,它调用了一个条件变量(< C++ > > >条件>变量>代码> void WaitForEvent(){ std::唯一锁(互斥锁); 而(!事件计数器){ 条件变量等待(锁定); } 返回; },c++,multithreading,testing,C++,Multithreading,Testing,现在我想对该方法的交互进行单元测试。因此我想调用WaitForEvent,然后调用PostEvent,它将通知条件变量并检查等待是否已停止 void PostEvent(){ // ... 条件变量通知所有(); } 我如何在单元测试中最好地做到这一点 到目前为止,我提出的唯一解决办法是 启动一个调用WaitForEvent 使线程在调用WaitForEvent后设置一个标志 在主线程中调用PostEvent 在主线程中等待x秒 检查是否已设置该标志 但是,我不喜欢不能在这里加入线程的事实。如

现在我想对该方法的交互进行单元测试。因此我想调用
WaitForEvent
,然后调用
PostEvent
,它将通知条件变量并检查等待是否已停止

void PostEvent(){
// ...
条件变量通知所有();
}
我如何在单元测试中最好地做到这一点

到目前为止,我提出的唯一解决办法是

  • 启动一个调用
    WaitForEvent
  • 使线程在调用
    WaitForEvent
    后设置一个标志
  • 在主线程中调用
    PostEvent
  • 在主线程中等待x秒
  • 检查是否已设置该标志
  • 但是,我不喜欢不能在这里加入线程的事实。如果我加入,那么如果
    WaitForEvent
    没有按预期解除阻止,我的测试将被阻止。此外,我不喜欢在单元测试中添加延迟

    有没有更好的办法解决我的问题?提前谢谢:)

    编辑1:我的第一个解决方案如下所示

    SomeClass-someu-class{};
    bool has_unblocked=false;
    std::线程阻塞_线程([&]{
    一些类。WaitForEvent();
    has_unblocked=true;
    });
    某个类的PostEvent();
    std::this_线程::sleep_for(std::chrono::毫秒(10));
    REQUIRE(has_unblocked==true);
    阻塞线程。连接();
    
    我在我的一些单元测试中做了类似的事情,这些测试涉及线程和线程之间的mashalling事件/消息。你提出的策略不错

    一个问题,你的单元测试只是简单地测试了 STD::FalthApple变量的行为,而不是用CONDYVAR实现的代码的行为。我总是告诉我的团队要小心,只需要测试平台和C++运行时的测试,因为我们知道。这很有效。我怀疑你的测试不仅仅是等待和发布代码,但这正是我想指出的。因为一旦您意识到这一点,就可以考虑在单元测试中重写等待和邮政编码。

    如果我加入,那么如果WaitForEvent未按预期解除阻止,我的测试将被阻止

    但是在成功的情况下,这并不重要,因为您的代码可以正常工作,并且测试可以很快完成。如果它真的永远阻塞,那么您的单元测试已经发现了一个真正的bug。这是件好事,对吗?(除了您的团队成员抱怨单元测试再次挂起之外。)

    但是,如果您想避免UT代码中出现死锁的可能性,您可以使用一种wait变体,它使用
    wait\u for
    代替
    wait
    。其中,产品代码可能不依赖于超时,但UT依赖于

    class SomeClass
    {
        bool _running_as_unittest;
        void WaitForEvent() {
          std::unique_lock<std::mutex> lock(mutex_);
          while (!event_counter_) {
            if (_running_as_unittest) {
                cond_var.wait(lock, FiveSeconds); // give the test a chance to escape
                if (!event_counter) {
                    _errorCondition = true;
                }
            }
            else {
               cond_var.wait(lock); // wait forever
            } 
          } 
          return;
        }
    …
    }
    
    class-SomeClass
    {
    作为单元测试运行的布尔;
    void WaitForEvent(){
    std::唯一锁(互斥锁);
    而(!事件计数器){
    如果(作为单元测试运行){
    cond_var.wait(lock,五秒钟);//给测试一个逃脱的机会
    如果(!事件计数器){
    _errorCondition=true;
    }
    }
    否则{
    cond_var.wait(lock);//永远等待
    } 
    } 
    返回;
    }
    …
    }
    
    然后您的测试代码:

      SomeClass some_class{};
      bool has_unblocked = false;
      some_class._running_as_unittest = true;
      some_class._errorCondition = false;
    
      std::thread blocking_thread([&] {
        some_class.WaitForEvent();
        has_unblocked = true;
      });
    
      some_class.PostEvent();
      for (int x = 0; (x < 500) && !has_unblocked; x++) {
           std::this_thread::sleep_for(std::chrono::milliseconds(10));
      }
    
      REQUIRE(has_unblocked == true);
      REQUIRE(someclass._errorCondition == false);
    
      // todo - if has_unblocked is false, you could consider invoking `blocking_thread.native_handle` and then invoking `pthread_kill` or `TerminateThread` as appropriate. instead of invoking `join`.
    
      blocking_thread.join();
    
    SomeClass-someu-class{};
    bool has_unblocked=false;
    某些类。运行作为单元测试的类=true;
    某些类。\u errorCondition=false;
    std::线程阻塞_线程([&]{
    一些类。WaitForEvent();
    has_unblocked=true;
    });
    某个类的PostEvent();
    对于(int x=0;(x<500)&&!已解锁;x++){
    std::this_线程::sleep_for(std::chrono::毫秒(10));
    }
    REQUIRE(has_unblocked==true);
    REQUIRE(someclass.\u errorCondition==false);
    //todo-HasununBuffice为false时,可以考虑调用“BuffjixTrime.nTyVeWaRead”,然后适当调用“pthRead Type”或“TealthType”。而不是调用“join”。
    阻塞线程。连接();
    
    在这种情况下,我通常使用
    std::async
    返回一个
    std::future
    ,并且我还指定操作超时,以避免在CI中卡住的测试

    #include <future>
    #include <condition_variable>
    #include <chrono>
    #include <mutex>
    
    class MySystem {
    public:
        MySystem() = default;
        std::future<bool> WaitForEvent(std::chrono::milliseconds timeout) {
            std::unique_lock<std::mutex> l(cv_m_);
            return std::async(std::launch::async,
                // for this lambda you need C++14
                [this, timeout, lock{std::move(l)}] () mutable {
                if (cv_.wait_for(lock, timeout) == std::cv_status::timeout) {
                    return false;
                }
                return true;
            });
        }
        void PostEvent() {
            std::lock_guard<std::mutex> guard(cv_m_);
            cv_.notify_all();
        }
    
    private:
        std::condition_variable cv_;
        std::mutex cv_m_;
    };
    
    TEST(xxx, yyy) {
        MySystem sut;
        auto result = sut.waitForEvent(std::chrono::seconds(1));
        ASSERT_FALSE(result.get());
        result = sut.waitForEvent(std::chrono::seconds(1));
        sut.PostEvent();
        ASSERT_TRUE(result.get());
    }
    
    #包括
    #包括
    #包括
    #包括
    类MySystem{
    公众:
    MySystem()=默认值;
    std::future WaitForEvent(std::chrono::毫秒超时){
    std::唯一锁定l(cv_m_);
    返回std::async(std::launch::async,
    //对于这个lambda,您需要C++14
    [this,timeout,lock{std::move(l)}]()可变{
    如果(cv_u.wait_ufor(锁定,超时)=标准::cv_u状态::超时){
    返回false;
    }
    返回true;
    });
    }
    void PostEvent(){
    标准:锁紧防护装置(cv_m_);
    cv_uu.notify_uall();
    }
    私人:
    std::条件变量cv;
    std::互斥cv_m_;
    };
    测试(xxx,yyy){
    MySystem-sut;
    自动结果=sut.waitForEvent(std::chrono::seconds(1));
    ASSERT_FALSE(result.get());
    结果=sut.waitForEvent(标准:计时:秒(1));
    sut.PostEvent();
    ASSERT_TRUE(result.get());
    }
    

    std::future
    节省了我手动创建和连接线程的工作量,并允许我以一种良好的方式检查操作结果(例如超时时的
    false
    )。在调用
    std::mutex
    之前锁定
    std::async
    可以保证在执行
    notify\u all
    之前,您的
    条件变量将开始等待,非常感谢-这回答了我的所有问题:)另外,我的测试实际上测试了更多的行为——我只是想在这里展示相关部分,以免混淆任何读者:我不喜欢为
    SomeClass
    (比如
    runnin)编写额外接口的想法