簡體   English   中英

多線程 UDP 服務器中 io_context 或 std::cout 的奇怪行為

[英]Strange behaviour of either io_context or std::cout in multi-threaded UDP server

我有一個使用boost\\asio創建的簡單 UDP 服務器,它現在只打印接收到的數據,如下所示。

using boost::asio::ip::udp;

enum { max_length = 2048 };

void server(boost::asio::io_context& io_context, unsigned short port)
{
    std::cout << "Server Created on port " + std::to_string(port) << " \n" << std::flush;
    udp::socket sock(io_context, udp::endpoint(udp::v4(), port));
    while(true)
    {
        udp::endpoint sender_endpoint;
        std::vector<char> v(max_length);
        sock.receive_from(boost::asio::buffer(v), sender_endpoint);
        for (int i = 0; i < v.size(); i++)
        {
            std::cout << v[i] <<std::flush;
        }
        std::cout << std::endl;
    }
}

我使用boost::thread創建了server函數的 3 個線程,並將其分配給thread_group

boost::asio::io_context io_context;

            boost::thread_group tg;

            boost::thread *t = new boost::thread(server, std::ref(io_context), 8889);
            boost::thread *t1 = new boost::thread(server, std::ref(io_context), 8890);
            boost::thread *t2 = new boost::thread(server, std::ref(io_context), 11111);

            tg.add_thread(t);
            tg.add_thread(t1);
            tg.add_thread(t2);

            tg.join_all();

為了測試服務器,我使用了Packet Sender 問題是輸出是... scrambled 當在 3 個端口上每秒(或多或少)同時發送一次數據包時,輸出稍微錯位,但是當將數據包頻率增加到每 0.1 秒一次時,輸出變得不可讀,如這兩個圖像所示。 我曾嘗試為每台服務器提供一個單獨的io_context對象,但輸出頻率高時保持不變。 有什么辦法可以避免這種情況嗎?

合乎邏輯(且正確)的解決方案是在std::cout上使用互斥。 您知道鎖的適當范圍(在您的情況下,只有一個 UDP 數據包,但std::cout無法猜測)。

奇特的解決方案是boost.asio.strand 你並不需要一個簡單的情況就是這樣,但因為你試圖使用boost.asio.io_context你應該知道,還有另一個類boost.asio像你預期可以工作。

std::cout自動為您做一些鎖定,單個打印操作不會與來自不同線程的另一個打印重疊。 但是,當您一次打印一個字符時,每個線程的輸出可能會重疊。 在每個打印字符后刷新也可能導致性能不佳。

如果您將要打印的內容構建為單個字符串,它應該正確打印:

    std::vector<char> v(max_length);
    size_t bytes = sock.receive_from(boost::asio::buffer(v), sender_endpoint);
    std::string str(v.data(), bytes);
    str += '\n';
    std::cout << str;

或者您可以跳過向量並直接保存到字符串:

    std:: string str(max_length);
    size_t bytes = sock.receive_from(boost::asio::buffer(str), sender_endpoint);
    str.resize(bytes)
    str += '\n';
    std::cout << str;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM