gpt4 book ai didi

c++ - std::thread 访问从共享库加载的函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:18:24 24 4
gpt4 key购买 nike

在 Ubuntu 上,我有一个共享库 mylibrary.so,它有一个函数 AlphaFunction。我想使用 dlopen 在 C++ 中加载此函数,然后在两个不同的线程中调用它。但是,这给了我运行时错误,大概是因为两个线程都试图访问存储函数的同一内存。

库本身通过 USB 控制机械臂,我得到的实际运行时错误是:Write 操作返回的 LIBUSB_ERROR_NO_DEVICE。

我知道如何使用 std::atomic 来处理共享变量,但是共享函数呢?

例如:

void Foo(int (*FooFunction)())
{
while(true)
{
FooFunction();
}
}

void Bar(int (*BarFunction)())
{
while(true)
{
BarFunction();
}
}


int main()
{
void* api_handle = dlopen("mylibrary.so", RTLD_NOW|RTLD_GLOBAL);
int (*MoveRobot)() = (int (*)()) dlsym(api_handle, "Move");

std::thread t1(Foo, MoveRobot);
std::thread t2(Bar, MoveRobot);

t1.join();
t2.join();

return 0;
}

最佳答案

我看了评论。这是一个涵盖所有问题的解决方案:

  • 机器人库不是线程安全的,并且
  • 对机器人库的所有调用必须在同一个线程上

这个答案提出了一个解决方案,其中启动第三个线程作为机器人请求编码器。其他线程将任务发布到该线程的队列中,一次执行一个任务,调用结果通过调用者可以等待的 future 返回。

#include <thread>
#include <mutex>
#include <queue>
#include <future>
#include <functional>

// these definitions here just to make the example compile
#define RTLD_NOW 1
#define RTLD_GLOBAL 2
extern "C" void* dlopen(const char*, int);
extern "C" void* dlsym(void*, const char*);


struct RobotCaller final
{
RobotCaller()
{
_library_handle = dlopen("mylibrary.so", RTLD_NOW|RTLD_GLOBAL);
_Move = (int (*)()) dlsym(_library_handle, "Move");

// caution - thread starts. do not derive from this class
start();
}

void start()
{
_robot_thread = std::thread([this]{
consume_queue();
});
}

~RobotCaller() {
if (_robot_thread.joinable()) {
std::unique_lock<std::mutex> lock(_queue_mutex);
_should_quit = true;
lock.unlock();
_queue_condition.notify_all();
_robot_thread.join();
}

// close library code goes here
}

std::future<int> Move()
{
return queue_task(_Move);
}

private:
void consume_queue() {
;
for(std::unique_lock<std::mutex> lock(_queue_mutex) ; !_should_quit ; lock.lock()) {
_queue_condition.wait(lock, [this]{
return _should_quit || (!_task_queue.empty());
});

if (!_task_queue.empty()) {
auto task = std::move(_task_queue.front());
_task_queue.pop();
lock.unlock();
task();
}
}
}

std::future<int> queue_task(int (*f)())
{
std::packaged_task<int()> task(f);
auto fut = task.get_future();
std::unique_lock<std::mutex> lock(_queue_mutex);
_task_queue.push(std::move(task));
return fut;
}

private:
// library management
void* _library_handle = nullptr;
int (*_Move)() = nullptr;

// queue management
std::thread _robot_thread;
std::queue<std::packaged_task<int()>> _task_queue;
bool _should_quit = false;
std::mutex _queue_mutex;
std::condition_variable _queue_condition;
};

void Foo(std::function<std::future<int>()> FooFunction)
{
while(true)
{
// marshal the call onto the robot queue and wait for a result
auto result = FooFunction().get();
}
}

void Bar(std::function<std::future<int>()> BarFunction)
{
while(true)
{
// marshal the call onto the robot queue and wait for a result
auto result = BarFunction().get();
}
}


int main()
{
RobotCaller robot_caller;

std::thread t1(Foo, std::bind(&RobotCaller::Move, &robot_caller));
std::thread t2(Bar, std::bind(&RobotCaller::Move, &robot_caller));

t1.join();
t2.join();

return 0;
}

关于c++ - std::thread 访问从共享库加载的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30128249/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com