创建非静态成员函数的pthread

时间:2018-02-01 11:31:40

标签: c++ linux pthreads

我有以下课程:

class Foo {
    private:
        Bar *_bar;
        void *run(void *);

    public:
        Foo(Bar *bar);
}

我希望Foo::Foo启动运行Foo::run的线程。

我知道可以使用std::thread完成此操作:

Foo::Foo(Bar *bar) : _bar(bar) {
    _thread = std::thread(&Foo::run, this);
}

问题是我需要为此线程设置优先级和调度策略 - 可以使用pthread来实现。

(非常)遗憾的是,我无法改变系统的设计,而且我必须在C'tor 内部产生线程。

pthread是一个C API,我无法弄清楚如何在非静态成员函数上运行它。以下尝试未编译:

Foo::Foo*(Bar *bar) : _bar(bar) {
    // attempt 1
    pthread_create(&thread, NULL, &Foo::run, this);
    // attempt 2
    pthread_create(&thread, NULL, (void* (*)(void *))(&Foo::run), this);
}

pthread_create手册页 - 第三个参数(start_routine)是指向返回void *和接收void *的函数的指针。

2 个答案:

答案 0 :(得分:0)

会员功能不像免费功能。他们需要一个类的实例可以调用。因此,类型系统对它们的处理方式不同,指向成员函数的指针与自由函数的常规指针不同。 public static BigDecimal monthsBetween(final Date start, final Date end, final ZoneId zone, final int scale ) { final BigDecimal no31 = new BigDecimal(31); final LocalDate ldStart = start.toInstant().atZone(zone).toLocalDate(); final LocalDate ldEnd = end.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); final int endDay = ldEnd.getDayOfMonth(); final int endMonth = ldEnd.getMonthValue(); final int endYear = ldEnd.getYear(); final int lastDayOfEndMonth = ldEnd.lengthOfMonth(); final int startDay = ldStart.getDayOfMonth(); final int startMonth = ldStart.getMonthValue(); final int startYear = ldStart.getYear(); final int lastDayOfStartMonth = ldStart.lengthOfMonth(); final BigDecimal diffInMonths = new BigDecimal((endYear - startYear)*12+(endMonth-startMonth)); final BigDecimal fraction; if(endDay==startDay || (endDay==lastDayOfEndMonth && startDay==lastDayOfStartMonth)) { fraction = BigDecimal.ZERO; } else { fraction = BigDecimal.valueOf(endDay-startDay).divide(no31, scale, BigDecimal.ROUND_HALF_UP); } return diffInMonths.add(fraction); } public static BigDecimal monthsBetween(final Date start, final Date end) { return monthsBetween(start, end, ZoneId.systemDefault(), 20); } 使用模板提供可以接受的便捷API。

当然,pthreads并不是模板化的,并且不会解释任何不具备自由功能的东西。要使它在对象上运行成员函数,您需要一个trampoline函数。可以衰减为自由函数指针的函数,包含在您作为void传递的实例上执行成员的代码。

如果您发现自己经常需要这些,您可以编写一个模板,为您生成它们。像这样:

std::thread

因此,如果您将template<class C, void* (C::* run_mem)()> // Member function without argumnets void* pthread_member_wrapper(void* data) { C* obj = static_cast<C*>(data) return (obj->*run_mem)(); } 定义为run,则可以在void *run();可访问的任何位置使用上述包装:

run

由于Foo::Foo*(Bar *bar) : _bar(bar) { pthread_create(&thread, NULL, pthread_member_wrapper<Foo, &Foo::run>, this); } 在类和成员函数指针上被模板化,因此您可以在任何可以访问该成员的范围内将其重用于任何类。它不必是pthread_member_wrapper本身的成员。

答案 1 :(得分:0)

C和C ++的调用约定完全不同,因为C ++函数(除非是静态的)需要知道哪个类的实例用它来调用它的成员函数。

你可以做的是有一个静态函数,传入的参数是实例指针。像这样:

class Foo
{
    private:
        Bar *_bar;

        static void *start_thread(void *ptr) { return dynamic_cast<MyThread *>(ptr)->run(); }

        void *run();  // Implement thread here.

    public:
        Foo(Bar *bar);
}

Foo::Foo(Bar *bar) : _bar(bar) {
    pthread_create(&thread, NULL, Foo::start_thread, this);
}