GoogleMock 在 Linux 上不是线程安全的吗?

Posted

技术标签:

【中文标题】GoogleMock 在 Linux 上不是线程安全的吗?【英文标题】:Is GoogleMock not thread safe on Linux? 【发布时间】:2017-06-25 19:51:37 【问题描述】:

我开始在 Windows 上测试 GoogleMock(1.8.0 版)。我想展示一个例子,它不是线程安全的。在成功证明这一点之后,我想证明相同的测试在 Linux 上运行良好。然而那失败了。那不符合我的预期。 由于 GoogleMock 文档说它在具有 pthread 的系统上是或应该是线程安全的,因此它在 Linux 上应该是线程安全的。我确实必须将-pthread 添加到链接器命令行来构建可执行文件。这意味着 GoogleMock 或 GoogleTest 确实使用 pthread。

这是我用于测试的代码:

#include <thread>
#include <vector>

#include "gmock/gmock.h"

class Dummy

public:
    virtual void SomeMethod(int) 
;

class DummyMock : public Dummy

public:
    MOCK_METHOD1(SomeMethod, void(int));
;

using ::testing::Exactly;

constexpr static int nrCallsPerThread = 100 * 1000;
constexpr static int nrThreads = 10;

TEST(SomeTest, Test100)

    DummyMock dummy;

    std::vector<std::thread> threads;
    for (int i = 0; i < nrThreads; i++)
    
        EXPECT_CALL(dummy, SomeMethod(i)).Times(Exactly(nrCallsPerThread));
        threads.emplace_back([&dummy, i]
        
            for (int j = 0; j < nrCallsPerThread; j++)
            
                dummy.SomeMethod(i);
            
        );
    

    for (auto& t: threads)
    
        t.join();
    


int main(int argc, char** argv)

    testing::InitGoogleMock(&argc, argv);
    return RUN_ALL_TESTS();

问题在于,在 Linux 上,并没有公开每次执行。但是使用--gtest_repeat=100 运行可执行文件的命中率接近100%。

在 Windows 上,使用 Visual Studio 2015,如果收到带有 Expression: vector iterator not decrementableDebug Assertion Failed! 消息。

在 Linux Ubuntu 17.04 上,当我从命令行运行 Debug 构建时,我得到 [ FATAL ] ../googletest-release-1.8.0/googletest/include/gtest/internal/gtest-port.h:1928:: pthread_mutex_lock(&amp;mutex_)failed with error 22

在 Linux 上的调试器中运行时,程序(经常)在 gtest-port.h 第 1100 行被中断,这是此调用堆栈中的第 2 行:

0 0x5555555a6633 testing::Cardinality::ConservativeUpperBound() const () (??:??)
1 0x5555555a1a13 testing::internal::ExpectationBase::CheckActionCountIfNotDone() const () (??:??)
2 0x555555563f98 testing::internal::TypedExpectation<void (int)>::ShouldHandleArguments(std::tuple<int> const&) const(this=0x5555557f58a0, args=std::tuple containing = ...) (../googletest-release-1.8.0/googlemock/include/gmock/gmock-spec-builders.h:1100)
3 0x55555556397d testing::internal::FunctionMockerBase<void (int)>::FindMatchingExpectationLocked(std::tuple<int> const&) const(this=0x7fffffffde38, args=std::tuple containing = ...) (../googletest-release-1.8.0/googlemock/include/gmock/gmock-spec-builders.h:1723)
4 0x555555563578 testing::internal::FunctionMockerBase<void (int)>::UntypedFindMatchingExpectation(void const*, void const**, bool*, std::ostream*, std::ostream*)(this=0x7fffffffde38, untyped_args=0x7fffde7fbe14, untyped_action=0x7fffde7fb7d0, is_excessive=0x7fffde7fb7c7, what=0x7fffde7fb900, why=0x7fffde7fba90) (../googletest-release-1.8.0/googlemock/include/gmock/gmock-spec-builders.h:1687)
5 0x5555555a265e testing::internal::UntypedFunctionMockerBase::UntypedInvokeWith(void const*) () (??:??)
6 0x55555555fcba testing::internal::FunctionMockerBase<void (int)>::InvokeWith(std::tuple<int> const&)(this=0x7fffffffde38, args=std::tuple containing = ...) (../googletest-release-1.8.0/googlemock/include/gmock/gmock-spec-builders.h:1585)
7 0x55555555f16c testing::internal::FunctionMocker<void (int)>::Invoke(int)(this=0x7fffffffde38, a1=1) (../googletest-release-1.8.0/googlemock/include/gmock/gmock-generated-function-mockers.h:101)
8 0x55555555ecb6 DummyMock::SomeMethod(this=0x7fffffffde30, gmock_a1=1) (/home/jos/Programming/ThreadSafeGMock/main.cpp:16)
9 0x55555555d31e SomeTest_Test100_Test::<lambda()>::operator()(void) const(__closure=0x5555557f5478) (/home/jos/Programming/ThreadSafeGMock/main.cpp:36)
10 0x55555555de98 std::_Bind_simple<SomeTest_Test100_Test::TestBody()::<lambda()>()>::_M_invoke<>(std::_Index_tuple<>)(this=0x5555557f5478) (/usr/include/c++/6/functional:1391)
11 0x55555555de22 std::_Bind_simple<SomeTest_Test100_Test::TestBody()::<lambda()>()>::operator()(void)(this=0x5555557f5478) (/usr/include/c++/6/functional:1380)
12 0x55555555ddf2 std::thread::_State_impl<std::_Bind_simple<SomeTest_Test100_Test::TestBody()::<lambda()>()> >::_M_run(void)(this=0x5555557f5470) (/usr/include/c++/6/thread:197)
13 0x7ffff7b0a83f ??() (/usr/lib/x86_64-linux-gnu/libstdc++.so.6:??)
14 0x7ffff76216da start_thread(arg=0x7fffde7fc700) (pthread_create.c:456)
15 0x7ffff735b17f clone() (../sysdeps/unix/sysv/linux/x86_64/clone.S:105)

既然它应该是线程安全的,我怀疑我做错了什么。但我没有看到什么。 还是我在 GoogleTest 或 GoogleMock 中遇到了错误?

【问题讨论】:

你还必须在编译器命令行中添加-pthread。 @n.m.为什么?编译器,或者更具体的预处理器,会根据 googlemock 和 googletest 头文件中的条件编译包含 pthreads 头文件。 因为那是how it works。 【参考方案1】:

来自精美手册:

重要提示:Google Mock 要求在调用模拟函数之前设置期望,否则行为是未定义。特别是,您不能将 EXPECT_CALL() 和对模拟函数的调用交错。

您的原始代码在我的系统 (cygwin) 上间歇性地出现错误 22,或者有时没有任何消息/错误代码。此修改完美无缺:

for (int i = 0; i < nrThreads; i++)

    EXPECT_CALL(dummy, SomeMethod(i)).Times(Exactly(nrCallsPerThread));


std::vector<std::thread> threads;
for (int i = 0; i < nrThreads; i++)

    threads.emplace_back([&dummy, i] ...

【讨论】:

谢谢你修复它。我试图实现的是创建一些示例,表明 GoogleMock 在 Windows 上不是线程安全的,但在 Linux 上是线程安全的。你@n.m.知道一个例子吗? 食谱link 说:Using Google Mock and Threads IMPORTANT NOTE: What we describe in this recipe is ONLY true on platforms where Google Mock is thread-safe. Currently these are only platforms that support the pthreads library (this includes Linux and Mac). To make it thread-safe on other platforms we only need to implement some synchronization operations in "gtest/internal/gtest-port.h". 回应我自己的评论。这就是谷歌模拟烹饪书目前(仍然)所说的。然而,当我查看gtest-port.cc 的内部结构时,它也被gmock 使用,我看到class Mutex 是使用::XxxCriticalSection 实现的。所以这本食谱可能在这个话题上已经过时了,仍然指的是对 1.7.0 及更早版本有效的内容。

以上是关于GoogleMock 在 Linux 上不是线程安全的吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查 googlemock 中作为 void 指针传递的字符串参数

Linux线程安全篇

Linux线程安全篇Ⅰ

GoogleMock:如何准确地期待一个带有特定参数的调用,并查看失败的诊断?

Linux线程安全篇Ⅱ

C/C++/Assembly 以编程方式检测超线程在 Windows、Mac 和 Linux 上是不是处于活动状态 [重复]