将模板参数传递给线程中的模板函数

Passing template argument to template function in a thread

本文关键字:函数 参数传递 线程      更新时间:2023-10-16

我是模板的新手,所以我决定为我正在编写的一些并发代码编写单元测试,但我似乎无法让它们编译。具体错误为:

error C2664: 'std::thread::thread(const std::thread &)' : cannot convert argument 1 from       'void (__cdecl *)(lock &)' to 'void (__cdecl &)(Utility_UnitTests::emptyLock &)'
1>          None of the functions with this name in scope match the target type
1>          w:code dumpsterutility_unittestsutspinlock.cpp(88) : see reference to function template instantiation 'void Utility_UnitTests::UTSpinLock::lockContension<Utility_UnitTests::emptyLock>(lock &)' being compiled
1>          with
1>          [
1>              lock=Utility_UnitTests::emptyLock
1>          ]

这个问题从编译器很清楚,我没有传递正确的类型,但我不知道如何修复它!提前感谢!

编辑:我忘了说,我用的是Visual Studio 2013
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace Utility_UnitTests
{
typedef utils::threading::SpinLock<utils::threading::backoff::empty> emptyLock;
typedef utils::threading::SpinLock<utils::threading::backoff::yield> yieldingLock;
typedef utils::threading::SpinLock<utils::threading::backoff::pause> pausingLock;
TEST_CLASS(UTSpinLock)
{
public:
    template<typename lock>
    void lockAndSleepT(lock &l)
    {
        l.lock();
        std::this_thread::sleep_for(std::chrono::nanoseconds(10));
        l.unlock();
    }
    template<typename lock>
    void lockContension(lock &l)
    {
        std::thread t1(&UTSpinLock::lockAndSleepT<lock>, this, std::ref(l));
        Assert::AreEqual(true, l.isLocked());
        t1.join();
        Assert::AreEqual(false, l.isLocked());
    }
    TEST_METHOD(testLockContension)
    {
        UTSpinLock::lockContension(m_emptySpin);
        UTSpinLock::lockContension(m_yieldingSpin);
        UTSpinLock::lockContension(m_pausingSpin);
    }
    private:
    emptyLock m_emptySpin;
    yieldingLock m_yieldingSpin;
    pausingLock m_pausingSpin;
};
}

首先,这肯定是MSVC实现中的一个bug。当std::thread的第一个参数是指向成员函数模板的指针时,它似乎遇到了麻烦。在我的机器上,64位编译器产生相同的错误消息,而32位编译器崩溃。值得庆幸的是,您可以通过多种方式解决这个问题,所有这些方法都不涉及直接将指向成员函数模板的指针传递给thread


选项1 -正如您所发现的,创建bind表达式并将其传递给thread工作。


选项2 -重写类,使其成为模板,而成员函数不是。

template<typename lock>
struct UTSpinLock
{
public:
    void lockAndSleepT(lock &l)
    {}
    void lockContension(lock &l)
    {
        std::thread t1(&UTSpinLock::lockAndSleepT, this, std::ref(l));
        t1.join();
    }
};

选项3 -保持类定义不变,并将指向成员函数模板的指针包装在std::mem_fn

std::thread t1(std::mem_fn(&UTSpinLock::lockAndSleepT<lock>), this, std::ref(l));

选项4—不再更改类定义,这次将lambda表达式传递给thread

std::thread t1([&, this](){ lockAndSleepT(l); });

特别感谢WhozCraig!我会接受他的回答,但是,出于某种原因,我不能。对于那些感兴趣的人,我更改了:

template<typename lock>
void lockContension(lock &l)
{
    std::thread t1(&UTSpinLock::lockAndSleepT<lock>, this, std::ref(l));
    Assert::AreEqual(true, l.isLocked());
    t1.join();
    Assert::AreEqual(false, l.isLocked());
}

:

template<typename lock>
void lockContension(lock &l)
{
    auto bounded = std::bind(&UTSpinLock::lockAndSleepT<lock>, this,     std::placeholders::_1);
    std::thread t1(bounded, std::ref(l));
    Assert::AreEqual(true, l.isLocked());
    t1.join();
    Assert::AreEqual(false, l.isLocked());
}