回调到虚函数

3

我正在一个嵌入式平台上进行一些线程相关的工作。这个平台提供了一个Thread类,并且它有一个start方法,可以接受一个函数指针,就像这样:

void do_in_parallel() {
    // Some stuff to do in a new thread
}

Thread my_thread;
my_thread.start(do_in_parallel);

问题在于无法传递参数。1 我想通过创建一个抽象类来解决这个问题,称为Thread2,它继承Thread(或者它可以只有一个Thread作为实例数据)。 Thread2将具有纯虚函数void run(),目标是将其传递给Thread::start(void*()),但我很快了解到成员函数指针具有不同的类型,不能像这样使用。我可以使run()静态,但是那样我仍然不能拥有多个实例,这就打败了整个目的(更不用说您不能拥有虚静态函数)。
是否有任何变通方法,而不需要更改原始的Thread类(考虑到它是我所困扰的库)?

1. 在许多情况下,全局变量可以是可用的解决方法,除了从相同的函数指针实例化多个线程的情况。在这种情况下,我想不出避免竞争条件的方法。


为什么从相同的函数指针创建多个线程会引入竞争条件? - Passer By
看看能否强制它使用std::bind或lambda。 - user4581301
3个回答

6
编写一个全局线程池。
它维护着一个任务队列,这些任务可以有状态。
当你将一个任务添加到队列中时,你可以选择立即请求它获得一个线程。或者你可以等待池中的线程完成它们正在做的事情。
池中的线程由提供的Thread类创建,并从池中获取它们的执行指令。在大多数情况下,它们应该弹出任务,执行它们,然后等待另一个任务准备就绪。
如果不允许等待,你仍然可以拥有一些全局线程管理器来存储线程的状态。
池/管理器返回一个类似于future的对象,并带有任何你想要的功能。提供任务的代码通过该对象与任务交互,而不是嵌入式的Thread类型。

3
如果允许锁定,可以编写一个简单的包装器。
void start(Thread& t, void (*fn)(void*), void* p)
{
    static std::mutex mtx;  // or any other mutex
    static void* sp;
    static void (*sfn)(void*);

    mtx.lock();
    sp = p;
    sfn = fn;

    t.start([]{
        auto p = sp;
        auto fn = sfn;
        mtx.unlock();
        fn(p);
    });
}

显然,这种方法不会有很好的可扩展性,所有线程创建都通过相同的锁进行,但这已经足够了。

请注意,这是不安全的异常情况,但我认为在嵌入式系统中可以接受。

在封装器到位后

template<typename C>
void start(Thread& t, C& c)
{
    start(t, [](void* p){
        (*(C*)p)();
    }, &c);
}

这使得任何可调用对象都可以使用。这个特定的实现将管理可调用对象生命周期的责任放在调用者身上。


可扩展性不是问题。在执行开始时,我只需要创建一些线程,所以这个方法非常有效。现在看来,互斥锁应该是解决方案。顺便说一下,我没有访问C++11的功能,但在这种情况下很容易解决。 - Dominick Pastore

0
你可以创建自己的线程分发机制(生产者-消费者队列),围绕特定于平台的线程构建。
我假设你已经拥有目标平台的互斥锁和条件变量/信号机制等同设施。
  • 创建一个线程安全的队列,可以接受函数对象。
  • run方法创建一个线程并在队列上等待。
  • 调用线程可以调用post()/invoke()方法,只需将函数对象插入到队列中即可。
  • 函数对象可以传递给调用线程所需的参数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接