我有两个想要推送数据并弹出数据的线程
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()中睡眠时间更长。
但实际上效率不高......
答案 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();
}