我有一个简单的客户端/服务器应用程序,其代码如下所述。
请在Linux中的一个shell中运行服务器,而在另一个shell中运行客户端。
首先启动服务器,然后启动客户端。
当服务器完成它的工作时,它会崩溃并出现以下异常:

抛出“std::system_error”实例后调用终止
what():避免资源死锁

这发生在函数 Service::HandleClient 中的 m_thread->join() 行
我不知道发生了什么.. 有人可以检查代码.. 我只是希望服务器应用程序也应该像客户端应用程序关闭一样正确关闭。

**服务器代码:**

#include <boost/asio.hpp>

#include <thread>
#include <atomic>
#include <memory>
#include <iostream>

using namespace boost;

class Service {
public:
    Service(){}

    void StartHandligClient(
        std::shared_ptr<asio::ip::tcp::socket> sock) {

        m_thread.reset(new std::thread (([this, sock]() {
            HandleClient(sock);
        })) );

    }

private:
    void HandleClient(std::shared_ptr<asio::ip::tcp::socket> sock) {
        while(1)
        {
            try {
                asio::streambuf request;
                std::cout << "Waiting to read \n";
                asio::read_until(*sock.get(), request, '\n');

                std::string s( (std::istreambuf_iterator<char>(&request)), std::istreambuf_iterator<char>() );
                std::cout << "Server got : " << s << "\n";

                // Emulate request processing.
                int i = 0;
                while (i != 1000000)
                    i++;

                std::this_thread::sleep_for(
                        std::chrono::milliseconds(500));

                // Sending response.
                std::string response = "Response\n";
                asio::write(*sock.get(), asio::buffer(response));
            }
            catch (system::system_error &e) {
                boost::system::error_code ec = e.code();
                if(ec == asio::error::eof)
                {
                    std::cout << "Breaking loop \n";
                    break;
                }
                std::cout << "Error occured! Error code = "
                    << e.code() << ". Message: "
                    << e.what();
            }
        }

        m_thread->join();

        // Clean-up.
        delete this;
    }
    std::unique_ptr<std::thread> m_thread;
};

class Acceptor {
public:
    Acceptor(asio::io_service& ios, unsigned short port_num) :
        m_ios(ios),
        m_acceptor(m_ios,
        asio::ip::tcp::endpoint(
        asio::ip::address_v4::any(),
        port_num))
    {
        m_acceptor.listen();
    }

    void Accept() {
        std::cout << "Server Accept() \n" << std::flush;
        std::shared_ptr<asio::ip::tcp::socket>
            sock(new asio::ip::tcp::socket(m_ios));

        std::cout << "BEFORE calling acceptor's accept function \n" << std::flush;
        m_acceptor.accept(*sock.get());
        std::cout << "AFTER calling acceptor's accept function \n" << std::flush;


        (new Service)->StartHandligClient(sock);
    }

    void close()
    {
        std::cout << "Inside Acceptor.close() \n" << std::flush;
        m_acceptor.close();
    }

private:
    asio::io_service& m_ios;
    asio::ip::tcp::acceptor m_acceptor;
};

class Server {
public:
    Server() : m_stop(false) {}

    void Start(unsigned short port_num) {
        m_thread.reset(new std::thread([this, port_num]() {
            Run(port_num);
        }));
    }

    void Stop() {
        m_stop.store(true);
        m_thread->join();
    }

private:
    void Run(unsigned short port_num) {
        Acceptor acc(m_ios, port_num);

        while (!m_stop.load()) {
            std::cout << "Server accept\n" << std::flush;
            acc.Accept();
        }
        acc.close();
    }

    std::unique_ptr<std::thread> m_thread;
    std::atomic<bool> m_stop;
    asio::io_service m_ios;
};

int main()
{
    unsigned short port_num = 3333;

    try {
        Server srv;
        srv.Start(port_num);

        std::this_thread::sleep_for(std::chrono::seconds(4));

        srv.Stop();
    }
    catch (system::system_error &e) {
        std::cout << "Error occured! Error code = "
            << e.code() << ". Message: "
            << e.what();
    }

    return 0;
}

**客户代码:**
#include <boost/asio.hpp>
#include <iostream>

using namespace boost;

class SyncTCPClient {
public:
    SyncTCPClient(const std::string& raw_ip_address,
        unsigned short port_num) :
        m_ep(asio::ip::address::from_string(raw_ip_address),
        port_num),
        m_sock(m_ios) {

        m_sock.open(m_ep.protocol());
    }

    void connect() {
        m_sock.connect(m_ep);
    }

    void close() {
        m_sock.shutdown(
            boost::asio::ip::tcp::socket::shutdown_both);
        m_sock.close();
    }

    std::string emulateLongComputationOp(
        unsigned int duration_sec) {

        std::string request = "EMULATE_LONG_COMP_OP "
            + std::to_string(duration_sec)
            + "\n";

        sendRequest(request);
        return receiveResponse();
    };

private:
    void sendRequest(const std::string& request)
    {
        std::cout << "Inside sendRequest : " << request << "\n";
        asio::write(m_sock, asio::buffer(request));
    }

    std::string receiveResponse() {
        asio::streambuf buf;
        asio::read_until(m_sock, buf, '\n');

        std::istream input(&buf);

        std::string response;
        std::getline(input, response);

        return response;
    }

private:
    asio::io_service m_ios;

    asio::ip::tcp::endpoint m_ep;
    asio::ip::tcp::socket m_sock;
};

int main()
{
    const std::string raw_ip_address = "127.0.0.1";
    const unsigned short port_num = 3333;

    try {
        SyncTCPClient client(raw_ip_address, port_num);

        // Sync connect.
        client.connect();

        std::cout << "Sending request to the server... " << std::endl;
        std::string response = client.emulateLongComputationOp(10);

        std::cout << "Response received: " << response << std::endl;
        sleep(2);

        // Close the connection and free resources.
        client.close();
    }
    catch (system::system_error &e) {
        std::cout << "Error occured! Error code = " << e.code()
            << ". Message: " << e.what();

        return e.code().value();
    }

    return 0;
}

最佳答案



事实上,不,我不会。问题已经分析过了:不能join当前线程(会死锁)。

但我可以做得更好:

捕获我的 Crystal 球,我猜你从一本名为 Boost.Asio C++ Network Programming Cookbook ¹ 的特定书中得到了这个例子,大约在第 139 页。

过了一会儿,当我把所有的代码味道加起来时,我认出了它(delete thism_stop.load() 把我推到了边缘)。

好消息是,我之前查看了该代码:

ASIO example code closing socket before it should

您可能可以从我在那里发表的特定评论中受益。

¹ 来自 packtpub:https://www.packtpub.com/application-development/boostasio-c-network-programming-cookbook

关于c++ - 崩溃 : terminate called after throwing an instance of 'std::system_error' what(): Resource deadlock avoided,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48076068/

10-13 08:09