c++ - C++11 中的异步构造函数

标签 c++ asynchronous c++11 constructor

有时我需要创建其构造函数需要很长时间才能执行的对象。 这会导致 UI 应用程序出现响应问题。

所以我想知道编写一个设计为异步调用的构造函数是否明智,方法是向它传递一个回调,当对象可用时会提醒我。

下面是示例代码:

class C
{
public:
    // Standard ctor
    C()
    {
        init();
    }

    // Designed for async ctor
    C(std::function<void(void)> callback)
    {
        init();
        callback();
    }

private:
    void init() // Should be replaced by delegating costructor (not yet supported by my compiler)
    {
        std::chrono::seconds s(2);
        std::this_thread::sleep_for(s);
        std::cout << "Object created" << std::endl;
    }
};

int main(int argc, char* argv[])
{
    auto msgQueue = std::queue<char>();
    std::mutex m;
    std::condition_variable cv;
    auto notified = false;

    // Some parallel task
    auto f = []()
    {
        return 42;
    };

    // Callback to be called when the ctor ends
    auto callback = [&m,&cv,&notified,&msgQueue]()
    {
        std::cout << "The object you were waiting for is now available" << std::endl;
        // Notify that the ctor has ended
        std::unique_lock<std::mutex> _(m);
        msgQueue.push('x');
        notified = true;
        cv.notify_one();
    };

    // Start first task
    auto ans = std::async(std::launch::async, f);

    // Start second task (ctor)
    std::async(std::launch::async, [&callback](){ auto c = C(callback); });

    std::cout << "The answer is " << ans.get() << std::endl;

    // Mimic typical UI message queue
    auto done = false;
    while(!done)
    {
        std::unique_lock<std::mutex> lock(m);
        while(!notified)
        {
            cv.wait(lock);
        }
        while(!msgQueue.empty())
        {
            auto msg = msgQueue.front();
            msgQueue.pop();

            if(msg == 'x')
            {
                done = true;
            }
        }
    }

    std::cout << "Press a key to exit..." << std::endl;
    getchar();

    return 0;
}

您认为这种设计有什么缺点吗?或者您知道是否有更好的方法?

编辑

按照 JoergB 回答的提示,我尝试编写一个工厂,负责以同步或异步方式创建对象:

template <typename T, typename... Args>
class FutureFactory
{
public:
    typedef std::unique_ptr<T> pT;
    typedef std::future<pT> future_pT;
    typedef std::function<void(pT)> callback_pT;

public:
    static pT create_sync(Args... params)
    {
        return pT(new T(params...));
    }

    static future_pT create_async_byFuture(Args... params)
    {
        return std::async(std::launch::async, &FutureFactory<T, Args...>::create_sync, params...);
    }

    static void create_async_byCallback(callback_pT cb, Args... params)
    {
        std::async(std::launch::async, &FutureFactory<T, Args...>::manage_async_byCallback, cb, params...);
    }

private:
    FutureFactory(){}

    static void manage_async_byCallback(callback_pT cb, Args... params)
    {
        auto ptr = FutureFactory<T, Args...>::create_sync(params...);
        cb(std::move(ptr));
    }
};

最佳答案

您的设计似乎非常具有侵入性。我看不出类必须知道回调的原因。

类似:

future<unique_ptr<C>> constructedObject = async(launchopt, [&callback]() {
      unique_ptr<C> obj(new C());
      callback();
      return C;
})

或者干脆

future<unique_ptr<C>> constructedObject = async(launchopt, [&cv]() {
      unique_ptr<C> ptr(new C());
      cv.notify_all(); // or _one();
      return ptr;
})

或者只是(没有 future ,但有一个带参数的回调):

async(launchopt, [&callback]() {
      unique_ptr<C> ptr(new C());
      callback(ptr);
})

应该也一样,不是吗?这些还确保只有在构造完整对象时(从 C 派生时)才调用回调。

将这些中的任何一个变成通用的 async_construct 模板应该不会太费力。

关于c++ - C++11 中的异步构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14685288/

相关文章:

c++ - C++ 中的指针和指针集合。如何正确删除

c++ - C++ 中的类/函数模板占用了我的二进制文件的百分比是多少?

c++ - 从容器中获取元素的常量资格的通用方法

C++ 关闭 Boost ASIO SSL 套接字的最佳方法是什么?

android - 所有异步任务完成后如何做某事?

c++ - 测试后无法取消 MPI 请求

c# - 异步 lambda : "a task was cancelled"

c++ - 了解函数指针和引用

c++ - 无法将枚举值传递给递归模板 (C++)

c++ - Python:有一个用户定义的函数作为输入,同时保持源代码不可访问?