我正在解决FAST协议的两个Feed仲裁问题。 如果你不熟悉它,请不要担心,我的问题实际上非常普遍。但我正在为那些感兴趣的人添加问题描述(你可以跳过它)。
所有UDP源中的数据在两个不同的多播IP上的两个相同的源(A和B)中传播。强烈建议客户端因可能的UDP数据包丢失而接收和处理这两个源。处理两个相同的馈送允许统计上降低分组丢失的可能性。 未在第一次显示消息的特定馈送(A或B)中指定。要仲裁这些订阅源,应使用在Preamble或标签34-MsgSeqNum中找到的消息序列号。利用前导码允许在不解码FAST消息的情况下确定消息序列号。 应使用以下算法处理来自Feed A和B的消息:
如果出现序列号中的间隙,则表示两个源(A和B)中的数据包丢失。客户端应启动其中一个恢复过程。但首先客户端应该等待一段合理的时间,由于数据包重新排序,丢失的数据包可能会稍晚一些。 UDP协议不能保证按顺序传送数据包。
// tcp recover algorithm进一步
我写了这么简单的课。它预先分配所有必需的类,然后接收特定seqNum
的第一个线程可以处理它。另一个线程将在以后放弃它:
class MsgQueue
{
public:
MsgQueue();
~MsgQueue(void);
bool Lock(uint32_t msgSeqNum);
Msg& Get(uint32_t msgSeqNum);
void Commit(uint32_t msgSeqNum);
private:
void Process();
static const int QUEUE_LENGTH = 1000000;
// 0 - available for use; 1 - processing; 2 - ready
std::atomic<uint16_t> status[QUEUE_LENGTH];
Msg updates[QUEUE_LENGTH];
};
实现:
MsgQueue::MsgQueue()
{
memset(status, 0, sizeof(status));
}
MsgQueue::~MsgQueue(void)
{
}
// For the same msgSeqNum should return true to only one thread
bool MsgQueue::Lock(uint32_t msgSeqNum)
{
uint16_t expected = 0;
return status[msgSeqNum].compare_exchange_strong(expected, 1);
}
void MsgQueue::Commit(uint32_t msgSeqNum)
{
status[msgSeqNum] = 2;
Process();
}
// this method probably should be combined with "Lock" but please ignore! :)
Msg& MsgQueue::Get(uint32_t msgSeqNum)
{
return updates[msgSeqNum];
}
void MsgQueue::Process()
{
// ready packets must be processed,
}
用法:
if (!msgQueue.Lock(seq)) {
return;
}
Msg msg = msgQueue.Get(seq);
msg.Ticker = "HP"
msg.Bid = 100;
msg.Offer = 101;
msgQueue.Commit(seq);
如果我们假设QUEUE_LENGTH是无穷大,这可以正常工作。因为在这种情况下,一个msgSeqNum =一个updates
数组项。
但是我必须使缓冲区循环,因为它不可能存储整个历史记录(数百万个数据包),并且没有理由这样做。实际上我需要缓冲足够的数据包来重建会话,一旦重建了会话,我就可以删除它们。
但是使用循环缓冲区会使算法复杂化。例如,假设我们有长度为1000的循环缓冲区。同时我们尝试处理seqNum = 10 000和seqNum = 11 000(这是非常不可能但仍然可能)。这两个数据包都将映射到索引updates
的数组0
,因此会发生冲突。在这种情况下,缓冲区应该“丢弃”旧数据包并处理新数据包。
使用locks
实现我想要的东西是微不足道的,但是在不同线程使用的循环缓冲区上编写lock-free
代码真的很复杂。所以我欢迎任何建议和建议如何做到这一点。谢谢!
答案 0 :(得分:0)
我不相信你可以使用环形缓冲区。可以在status[]
数组中使用散列索引。即,hash = seq % 1000
。问题是序列号由网络决定,您无法控制它的排序。您希望根据此序列号锁定。您的数组不需要无限,只需序列号的范围;但这可能比实际更大。
我不确定序列号被锁定时发生了什么。这是否意味着另一个线程正在处理它?如果是这样,您必须维护一个子列表以进行哈希冲突,以解决特定的序列号。
您也可以将数组大小视为2的幂。例如,1024将允许hash = seq & 1023;
这应该非常有效。