cpp-ipc icon indicating copy to clipboard operation
cpp-ipc copied to clipboard

bug反馈:发送方速度超出接收方时的异常现象

Open Jaf932074323 opened this issue 2 years ago • 4 comments

当发送方速度很快,接收方跟不上的时候,接收方会异常阻塞卡死,怀疑是同步控制有问题。 在win平台下,vs2019编译环境,64位debug,创建控制台项目,有如下源代码: #include #include #include #include #include "libipc/ipc.h"

constexpr char const name__[] = "ipc-chat"; ipc::channel sender__{ name__, ipc::sender }; ipc::channel receiver__{ name__, ipc::receiver };

int main() { std::thread receiver( { std::cout << " Start recv.\n";

		while (1)
		{
			ipc::buff_t buf = receiver__.recv(); // 阻塞
			if (buf.empty())
			{
				continue;
			}

			std::string strRecv(buf.get<char const*>(), buf.size());
			if (strRecv == "quit") break;
			std::cout << "Recv:" + strRecv;

			std::this_thread::sleep_for(std::chrono::milliseconds(100));
		}
		std::cout << " receiver is quit...\n";
	});

std::thread sender([]()
	{
		std::cout << " Start send.\n";

		std::string strSend;
		for (int i = 1; i < 10000; ++i)
		{
			strSend = std::to_string(i) + ",________________________________________________.\n";
			sender__.send(strSend.c_str(), strSend.size());
		}

		strSend = "quit";
		while (true)
		{
			bool bSuccess = sender__.send(strSend.c_str(), strSend.size());
			if (bSuccess) break;
		}
		std::cout << " Sender is quit...\n";
	});

receiver.join();
sender.join();
receiver__.disconnect();
sender__.disconnect();
return 0;

}

执行一段时间后,发送会提示: fail: send, there is no receiver on this connection. 在暂停断点调试,会发现receiver接收线程阻塞在了cpp-ipc\src\libipc\platform\waiter_win.h文件的45行处,永远不退出了,阻塞代码: switch ((ret = ::WaitForSingleObject(h_, ms))) {

Jaf932074323 avatar Oct 15 '21 04:10 Jaf932074323

这是因为接收方来不及收取消息,会造成消息堆积。 目前消息队列总长度为255,超出长度,又过了100ms超时仍然堆积的情况,sender会通过force_push强行写入。 force_push强行写入会清理导致超时的receiver(因为可能意外崩溃或卡死,不能无限制的每次都等待),因此对接收来不及的receiver来说,相当于被踢了。 你的例子里,receiver并没有死,而是人为制造了100ms等待,因此receiver被踢了以后就无限等在那了。

你这个情况我后面考虑加个机制,当receiver被踢掉以后自己需要知道,这样recv就会直接退出了。

mutouyun avatar Oct 16 '21 03:10 mutouyun

@mutouyun 这个是我在进程间通信时,遇到的问题。 因为发送端只管发送,速度非常快。而接收端还需要处理数据,速度就跟不上。 上图是我根据实际遇到的问题,写的一个问题复现demo。100ms等待就在模拟接收端处理数据。 force_push强行写入的话,会导致接收端掉包的情况。 有不有同步发送功能呢,在发送的时候,等待接端接收到数据之后,发送函数再返回呢。或者每次发送的时候获取一下消息队列的状态,队列满的时候发送方阻塞等待一下。 另外有一个问题,开源库支持多发多收、单发多收,但是没有找到单发单收功能。 最后,非常感谢你们的开源库哟,方便了不少。

Jaf932074323 avatar Oct 17 '21 15:10 Jaf932074323

而接收端还需要处理数据,速度就跟不上。

这是不行的,这样必然会导致消息丢失。 正确的做法是,你需要自己做一层隔离,接收消息应该放到你自己的内存队列里做cache,处理的时候从cache中取。

等待接端接收到数据之后,发送函数再返回 每次发送的时候获取一下消息队列的状态,队列满的时候发送方阻塞等待一下

如上这种逻辑,不是ipc通讯组件需要考虑的,需要的是类似 rpc 的逻辑。 你需要基于ipc自己实现一套,或者直接使用现成的rpc框架,比如: https://github.com/alephzero/alephzero https://github.com/eclipse-iceoryx/iceoryx https://github.com/qicosmos/rest_rpc

另外有一个问题,开源库支持多发多收、单发多收,但是没有找到单发单收功能

参见:https://github.com/mutouyun/cpp-ipc/wiki/Tutorial#%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8A%9F%E8%83%BD

mutouyun avatar Oct 18 '21 14:10 mutouyun

发送端在堵塞的时候其实是有等待的,你可以在 include/libipc/def.h 中配置 default_timeout,或者在 send 调用的时候传入 timeout(单位ms)

mutouyun avatar Oct 18 '21 14:10 mutouyun