我正在设计一个公开同步和异步操作的C ++ API。所有操作都可能失败,必须报告失败。异步操作必须提供一种在完成时执行延续的方法。我试图以最可读和一致的方式设计API。
这是一个说明我现在的设计的例子:
#include <memory>
#include <future>
using namespace std;
class Error {
public:
Error(int c, string desc) : code(c), description(desc) {}
int code;
string description;
};
template<typename T>
class Callback {
public:
virtual void completed(const T& result, unique_ptr<Error> error) = 0;
};
template<typename T>
class PrintCallback : public Callback<T> {
public:
void completed(const T& result, unique_ptr<Error> error) override {
if (nullptr != error) {
printf("An error has occured. Code: %d Description: %s\n",
error->code, error->description.c_str());
} else {
printf("Operation completed successfully. Result: %s\n",
to_string(result).c_str());
}
}
};
class API {
public:
void asyncOperation(shared_ptr<Callback<int>> callback) {
thread([callback]() {
callback->completed(5, nullptr);
}).detach();
}
int syncOperation(unique_ptr<Error>& error) {
return 5;
}
void asyncFailedOperation(shared_ptr<Callback<int>> callback) {
thread([callback]() {
callback->completed(-1, unique_ptr<Error>(new Error(222, "Async Error")));
}).detach();
}
int syncFailedOperation(unique_ptr<Error>& error) {
error = unique_ptr<Error>(new Error(111, "Sync Error"));
return -1;
}
};
我不喜欢使用error out参数进行同步操作以及同步和异步签名之间的不一致。 我正在讨论两种选择:
std::promise
和std::future
,并使用例外报告失败。对于异步操作,将返回std::future
,并在发生故障时抛出get()
。同步操作只会在出现故障时抛出。这种方法感觉更清晰,因为错误处理不会打击方法签名,异常是在C ++中进行错误处理的标准方法。但是,为了获得结果,我将不得不调用future::get()
,所以如果我不想阻止,那么我必须启动另一个线程来等待结果。异步操作的延续在实际设置std::promise
上的结果的线程上运行也很重要。这种方法是这个问题的公认答案 - Synchronous and ASynchronous APIs。我想知道:
谢谢!
答案 0 :(得分:1)
答:避免额外线程的一种方法是将线程池与任务队列一起使用。该方法仍然使用额外的线程,但线程的数量是系统固定的,而不是与创建的任务数量成比例。
问:如果替代#2的缺点超过其优点(特别是额外的线程)。
答:我不这么认为。
问:如果还有其他方法我没有考虑过。
答:是的。在我看来,最好的方法是使所有内容异步,为boost :: asio提供类似的API,利用boost :: asio :: io_service和lambda函数,并实现线程池和任务队列。您可以通过异步实现sync作为包装器,如下所示:进行异步调用并等待std :: condition_variable。异步调用的回调信号表示condition_variable。
问:哪种方法可视为可读性和一致性的最佳选择。
除此之外,在我看来,你不应该实现自己的Error类。看看std :: error_code(以及error_condition,error_category)。一篇不错的文章是http://blog.think-async.com。有人已经为你解决了这个问题。