我有以下课程:
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 *
的函数的指针。
答案 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);
}