1

以下 C++ 代码片段使用 Microsoft 的 C++ Rest SDK。我不明白为什么第一个片段有效而其他片段无效。我假设差异是由于对象破坏和范围规则造成的。我正在寻找关于为什么第一个片段有效而其他片段挂在 close() 上的解释。此外,SDK 可以做些什么来消除未来的错误。一些非常聪明的人看了片段,但从来没有看到问题。

第一个代码片段。该片段有效并完整显示。随后的代码片段替换其中的标记代码。请关注差异而不是其他干扰。通过在浏览器中发出单个 GET 请求并单步执行代码来测试代码。在所有情况下, request.reply() 只执行一次。

    boost::lockfree::spsc_queue<web::http::http_request, boost::lockfree::capacity<1024>> queue;
web::http::experimental::listener::http_listener listener(U("http://localhost:3901"));
listener.support([&](web::http::http_request request)
{
    queue.push(request);
});
listener.open().wait();
std::cout << "listening ... hit enter to initiate shutdown." << std::endl;
std::getchar();
// BEGIN CODE IN QUESTION
while (!queue.empty())
{
    web::http::http_request request;
    if (queue.pop(request))
        request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
}
// END CODE IN QUESTION
listener.close().wait();

第二个代码片段。挂在 close() 上。

    // hangs on close().wait()
web::http::http_request request;
while (queue.try_pop(request))
{
    request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
}

第三个代码片段。挂在 close() 上。

    // hangs on close().wait(). Outer braces make no difference.
 {
    web::http::http_request request;
    while (queue.try_pop(request))
    {
        request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
        request.~http_request();
    }
}

第四代码片段。挂在 close() 上。外大括号没有区别。

    // hangs on close().wait()
{
    web::http::http_request request;
    while (queue.try_pop(request))
    {
        request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
        request.~http_request();
    }
    request.~http_request();
}

更新:支持 Matt McNabb 的解释,如果我只发出一个 GET,则以下代码有效。我只是删除了循环来处理单个 GET。为了避免挂起,需要显式调用析构函数,但这是不正确的做法。

    web::http::http_request request;
requests.pop(request);
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
    request.~http_request();

更新:循环后的显式析构函数调用使程序为单个 GET 工作。但是,两个或更多 GET 会引发异常。我不确定为什么。

    web::http::http_request request;
while (queue.try_pop(request))
{
    request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
}
request.~http_request();
4

2 回答 2

2

这些示例中的每一个的问题似乎都是相同的:请求对象的构造和销毁不匹配。我很少看到做错事的这种聪明才智。

简单的解决方案是:

  1. 在块内声明对象,此时它将被分配。
  2. 不要显式调用析构函数(这不是一个好主意)。
  3. 当块退出时,对象将被销毁。

似乎需要在调用 close() 之前将其销毁,这是合理的。


我的意思是第二个例子是唯一一个对象根本没有被破坏的例子,它也失败了。我认为这是由于其他原因在此代码中不可见。

于 2014-06-21T14:37:23.940 回答
1

免责声明:在对该库没有任何了解的情况下,这是相当危险的

#include <iostream>
using namespace std;

class Obj {
public:
    Obj() {
        cout << "Constructor" << endl;
    }
    ~Obj() {
        cout << "Destructor" << endl;
    }
};

int main() {
    {
        Obj ea;
        ea.~Obj();
    }
    return 0;
}

输出:

Constructor 
Destructor 
Destructor

如果有要释放的资源或要执行的操作来清理请求,那么您在每种情况下都会造成很多麻烦,除非您执行以下步骤:

  1. pop通过副本(或try_pop)获取请求
  2. 处理请求
  3. 一次销毁和清理请求

在上面的片段中:

  1. 对象从队列中复制、处理和销毁。他们每一个人。很好
  2. 对象被复制、处理但不被销毁。挂起
  3. 对象被复制、处理、销毁,然后再次销毁。挂起
  4. 3还差。
  5. 对象被复制、处理和销毁。对于 listener 来说很好,它可能会在函数范围的末尾触发问题。
  6. 该对象被复制、处理,其中只有一个正在调用析构函数以进行清理——因此只有一个请求。一个请求罚款
于 2014-06-21T14:46:00.313 回答