使用C ++类成员函数作为C回调函数,线程安全版本
原始问题,效果很好回答如何制作非线程安全版本.
The original question, got a great answer as to how to do the non thread safe version.
这是代码,我尝试对其进行一些修改以使其正常工作:
Here is the code, which I've tried to slightly modify to get to work:
#include <stdio.h>
#include <functional>
#include <thread>
void register_with_library(int (*func)(int *k, int *e)) {
int x = 0, y = 1;
int o = func(&x, &y);
}
typedef int (*callback_t)(int*,int*);
class A {
template <typename T>
struct Callback;
template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
template <typename... Args>
thread_local static Ret callback(Args... args) {
func(args...);
}
thread_local static std::function<Ret(Params...)> func;
};
public:
A();
~A();
int e(int *k, int *j);
private:
callback_t func;
};
template <typename Ret, typename... Params>
thread_local std::function<Ret(Params...)> A::Callback<Ret(Params...)>::func;
A::A() {
Callback<int(int*,int*)>::func = std::bind(&A::e, this, std::placeholders::_1, std::placeholders::_2);
printf("1. C callback function ptr %p, C++ template function ptr %p Object ptr %p \n",func, Callback<int(int*,int*)>::func, this) ;
func = static_cast<callback_t>(Callback<int(int*,int*)>::callback);
printf("2. C callback function ptr %p\n",func) ;
register_with_library(func);
}
int A::e(int *k, int *j) {
return *k - *j;
}
A::~A() { }
int main() {
std::thread t1 = std::thread { [](){ A a;}};
std::thread t2 = std::thread { [](){ A a;}};
t1.join();
t2.join();
}
结果是
function ptr 0x400eef
function ptr 0x400eef
考虑到我有多个线程创建不同的对象,如何使这项工作正常工作以为每个新对象创建新的回调?
How would one make this work properly to create new callbacks for each new object, considering I have multiple threads creating different objects?
如e.jahandar所建议,使用thread_local可以部分解决该问题(仅当每个线程创建1个对象时).因此,Callback<int(int*,int*)>::func
是基于线程分配的.虽然,此问题仍然存在Callback<int(int*,int*)>::callback
.
As suggested by e.jahandar, using thread_local works to partially resolve the issue (only if there is 1 object created per thread). Thanks to this, Callback<int(int*,int*)>::func
is allocated on a thread basis. Although, the issue persists with Callback<int(int*,int*)>::callback
.
没有thread_local:
Without thread_local:
1. C callback function ptr 0x403148, C++ template function ptr 0x609180 Object ptr 0x7ff9ac9f3e60
2. C callback function ptr 0x403673
1. C callback function ptr 0x4031a6, C++ template function ptr 0x609180 Object ptr 0x7ff9ad1f4e60
2. C callback function ptr 0x403673
with thread_local:
with thread_local :
1. C callback function ptr 0x403230, C++ template function ptr 0x7fc1ecc756d0 Object ptr 0x7fc1ecc74e20
2. C callback function ptr 0x403701
1. C callback function ptr 0x4031d2, C++ template function ptr 0x7fc1ec4746d0 Object ptr 0x7fc1ec473e20
2. C callback function ptr 0x403701
如果每个线程只需要一个特定对象的实例,则可以使用__thread存储类为对象指针使用全局变量,__thread使全局变量对该线程唯一
If each thread just need one instance of specific object, you can use a global variable for object pointer with __thread storage class, __thread makes global variables unique to that thread.
将具有静态成员的单调类用于回调是另一种解决方案,就像先前的解决方案一样,您可以使用__thread来为每个线程分离单调类实例.
Using monotonic class with static member for callback is another solution, like previous solution, you can use __thread for separating monothonic class instances for each thread.
还请注意,__thread不是标准的东西
Also be aware, __thread isn't standard thing
修改
这是一个例子
class.h
class someClass{
private:
someMethod(){ ... }
}
class.cpp
class.cpp
__thread void * objectPointer;
void initialize(){
someClass * classPtr = new someClass();
objectPointer = (void *) classPtr;
}
void * callbackFunction(void * args){
someClass * obj = objectPointer;
obj->someMethod();
}