2015-05-08 34 views
2

在Ubuntu上,我有一個共享庫mylibrary.so,函數AlphaFunction。我想用C++加載這個函數,使用dlopen,然後在兩個不同的線程中調用它。但是,這給我帶來了運行時錯誤,大概是因爲這兩個線程都試圖訪問存儲函數的同一個內存。std ::線程訪問從共享庫加載的函數

庫本身控制通過USB機器人手臂,實際運行時錯誤我得到的是:LIBUSB_ERROR_NO_DEVICE returned by the Write operation.

我知道如何使用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; 
} 
+0

您還沒有用'extern「C''定義'MoveRobot'。如果您使用的是C++編譯器,則它的名稱已被改名。請參閱http://tldp.org/HOWTO/C++-dlopen/thesolution.html#externC – jiveturkey

+0

根據「MoveRobot」的內部結構可能無法正常工作,所以我不會將此作爲答案,但是您是否嘗試限制訪問該函數通過將調用包裝爲'FooFunction'和'BarFunction'與'std :: mutex?' – user4581301

+0

@jnbbender誰關心'MoveRobot',它是一個自動變量'main()'。我認爲你的意思是''移動''mylibrary.so'庫。 – WhozCraig

回答

1

我看了一下評論。下面是一個涵蓋了所有問題的辦法:

  • 機器人庫不是線程安全的機器人庫中的所有呼叫都必須在同一個線程

這個答案,並

  • 提出了一個解決方案第三個線程啓動,充當機器人請求編組器。其他線程將任務發佈到此線程的隊列中,每次執行一個任務,並通過調用者可以等待的未來返回調用結果。

    #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; 
    }