【问题标题】:Best way for waiting for callback to finish等待回调完成的最佳方式
【发布时间】:2015-02-23 12:26:37
【问题描述】:

在下面的代码中,main() 函数调用 request() 函数,该函数调用了 mm_th_done_cb() 的 th_request_async() 函数。

只有在 mm_th_done_cb() 执行后才能在 main 中继续进行的最佳和有效方法是什么。

虚拟代码

int mm_th_done_cb(int error_code, th_result_s* th_result, void* user_data)
{
    return 0;
}

void request()
{
    th_request_s MyItemInfo;
    strncpy(MyItemInfo.origin_path, szUrl, 1024+1);
    MyItemInfo.orientation = 0;
    MyItemInfo.func = mm_th_done_cb;
    MyItemInfo.used_cache = 1;
    th_request_async(MyItemInfo);
}


int main()
{
    request();
    // Here I need to do something only after mm_th_done_cb() has been excuted.
}

【问题讨论】:

  • 在 free 语句之前将调用设为 NULL。

标签: c++ multithreading synchronization


【解决方案1】:

你可以使用std::promise:

std::promise<int> promise;

int mm_th_done_cb(int error_code, th_result_s* th_result, void* user_data)
{
    promise.set_value(error_code /*this value will be returned by the future.get()*/);
    return 0;
}

int main()
{
    std::future<int> future = promise.get_future();
    request();
    int value = future.get();
    return 0;
}

如果您不需要从回调中返回任何值,则可以使用 std::promise&lt;void&gt;std::future&lt;void&gt; 对。

吴强回答中的两个例子都是错误的。

1.

#include <future>
int main()
{
    request();

    // WRONG: Here we don't want to call 'mm_th_done_cb' ourselves.
    std::future<int> myFuture = std::async(mm_th_done_cb);

    //wait until mm_th_done_cb has been excuted;
    int result = myFuture.get();
}

2.

#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;

int mm_th_done_cb(int error_code, th_result_s* th_result, void*     user_data)
{
    cv.notify_one();
    return 0;
}

int main()
{
    request();

    // WRONG: If the 'request' finishes quickly, then the 'mm_th_done_cb'
    // callback will be called and will notify the condition variable before 
    // the following lines execute, i.e. before the main thread starts 
    // waiting on the condition variable. Thus the 'cv.wait(lck)' will 
    // never return.

    unique_lock<std::mutex> lck(mtx);
    cv.wait(lck);
    return 0;
}

【讨论】:

    【解决方案2】:

    如果 C++11 可用,你可以 std::future

    #include <future>
    int main()
    {
        request();
        std::future<int> myFuture = std::async(mm_th_done_cb);
        //wait until mm_th_done_cb has been excuted;
        int result = myFuture.get();
    }
    

    或者你可以使用同步机制。比如condition_variable,它是跨平台的。

    #include <condition_variable>
    std::mutex mtx;
    std::condition_variable cv;
    int mm_th_done_cb(int error_code, th_result_s* th_result, void* user_data)
    {
        cv.notify_one();
        return 0;
    }
    
    int main()
    {
        request();
        unique_lock<std::mutex> lck(mtx);
        cv.wait(lck);
        return 0;
    }
    

    【讨论】:

    • th_request_async();函数调用传递给 MyItemInfo.func = mm_th_done_cb 的 mm_th_done_cb 函数;在 mm_th_done_cb 回调函数中,我检索了我调用 th_request_async 的所需值。
    • 在我的情况下,我必须调用 3 个类似的函数来获取值,在此之前我必须等待。我需要以最佳方式处理此类情况的建议。
    • Main() 正在调用 request() 可以请求正在调用 th_request_async() 这是一个库函数,它正在调用注册的回调函数 mm_th_done_cb()
    • c++11 也有信号量吗?
    • @mafu 是对的,这个答案是不正确的。将锁和信号与回调一起使用是非常糟糕的设计,并且会导致未知行为。
    【解决方案3】:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-09
      • 2016-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多