C ++使用两个线程

时间:2018-03-28 09:46:52

标签: c++ boost-asio

我有两个想要推送数据并弹出数据的线程

m_collectThread = std::thread([&] {m_io_service.run();}); 
m_recognizeThread = std::thread([this]{pop();});

当my_pipe中的数据触发push()

void test::push()
{
     cout << __func__ << endl;

     boost::asio::async_read(m_pipe, boost::asio::buffer(m_buf),
            boost::asio::transfer_all(),
            boost::bind(&test::push,
            this,   /* add this if bind class member function */
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
}

和pop()总是运行(糟糕的主意?

void test::pop()
{
    while(true)
    {
        cout << __func__ << endl;
        usleep(200);
    }
}

两个线程在开始时运行良好,但过了一段时间后push()得到的机会越来越少

out out like: 的

开始:

  

     

弹出

     

     

弹出

  

     

弹出

     

弹出

     

弹出

     

弹出

     

弹出

     

     

弹出

     

弹出

     

弹出

     

弹出

     

弹出

这不是我想要的,我怎样才能让它变得更好?

[编辑]

我发现m_pipe的来源是一个音频流,并将数据放入32字节/毫秒。

避免总是弹出的粗略方法是在pop()中睡眠时间更长。

但实际上效率不高......

1 个答案:

答案 0 :(得分:0)

  

警告

     

这个答案解决代码中最大的潜在错误(未显示),因为你没有在m_buf(和其他成员?)周围指出任何线程同步(锁)

     

这意味着您同时使用来自多个线程的共享资源。如果你这样做,那就是Data Race并导致Undefined Behaviour

是的,紧密循环是一个坏主意。

使用以下代码:

<强> Live On Coliru

#include <boost/asio.hpp>
#include <boost/optional.hpp>
#include <boost/bind.hpp>
#include <thread>
#include <iostream>

namespace ba = boost::asio;

struct Test {
    ba::io_service m_io_service;
    boost::optional<ba::io_service::work> m_work { m_io_service };
    std::thread m_collectThread {[&] {m_io_service.run();}}; 
    std::thread m_recognizeThread {[this]{pop();}};

    ba::ip::tcp::socket m_pipe { m_io_service };
    char m_buf[4];

    Test() {
        m_pipe.connect({{}, 6767});
        push();
    }

    void push(boost::system::error_code ec = {}, size_t = 0)
    {
        std::cout << __func__ << " " << ec.message() << std::endl;

        if (ec) return;

        using namespace ba::placeholders;
        ba::async_read(m_pipe,
                ba::buffer(m_buf),
                ba::transfer_all(),
                boost::bind(&Test::push, this, error, bytes_transferred));
    }

    void pop()
    {
        while(true)
        {
            std::cout << __func__ << std::endl;
            usleep(200);
        }
    }

    ~Test() {
        m_work.reset();
        if (m_recognizeThread.joinable())
            m_recognizeThread.join();
        if (m_collectThread.joinable())
            m_collectThread.join();
    }
};

int main() {
    Test t;
}

我运行的服务器上写着&#34; HELLO&#34;每100毫秒:

for a in {1..100}; do sleep .1; netcat -l -p 6868 <<< HELLO; done

然后您可以通过运行./sotest | uniq -c

等程序来查看
      3 pop
      1 push Success
   1074 pop
      1 push Success
   3681 pop
      2 push Success
   3701 pop
      1 push Success
   3689 pop
      2 push Success
   3687 pop
      1 push Success
   3705 pop
      1 push pop

你可以看到,每次推动都有成千上万的流行音乐。那效率很低。

排队

为什么不使用排队?

队列是这里的自然解决方案,除非您需要超低延迟或极高吞吐量(在这种情况下,无锁队列是下一个逻辑步骤)。

事实上,io_service 是一个队列,所以您可以这样做: Live On Coliru

事实上,我进一步简化并删除了其他帖子和work

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>

namespace ba = boost::asio;

struct Test {
    ba::io_service& m_io_service;
    ba::ip::tcp::socket m_pipe { m_io_service };
    char m_buf[4];

    Test(ba::io_service& io) : m_io_service(io) {
        m_pipe.connect({{}, 6767});
        read_loop();
    }

    void push(size_t len) {
        std::cout << __func__ << std::endl;

        m_io_service.post(
            boost::bind(&Test::handle_message, this, std::string(m_buf, len)));
    }

    void read_loop() {
        using namespace ba::placeholders;
        ba::async_read(m_pipe,
                ba::buffer(m_buf),
                ba::transfer_all(),
                boost::bind(&Test::on_received, this, error, bytes_transferred));
    }

    void on_received(boost::system::error_code ec, size_t len) {
        if (len) push(len);
        if (!ec) read_loop();
    }

    void handle_message(std::string const& data) {
        std::cout << "Handling '" << data << "'\n";
    }
};

int main() {
    ba::io_service io;
    Test t(io);

    io.run();
}