我正在制作用于使用 C 语言控制各种嵌入式设备的小型库。我正在使用 UDP 套接字与每个设备进行通信。设备向我发送各种有趣的数据、警报和通知,同时它们发送一些由库内部使用但用户可能不感兴趣的数据。所以,我实现了一个回调方法,用户可以在每个设备上注册一个带有一些有趣事件的回调函数。现在,这个库的整体设计是这样的:-
- 我有两个线程正在运行。
- 在其中一个线程中,有一个无限
while
事件循环,它使用select
并non-blocking sockets
保持与每个设备的通信。 - 基本上,每次我从任何设备收到一个数据包时,我都会去掉一些无用信息的 20 个字节的标头,并添加我自己的标头,其中包含
DEVICE_ID
(REQUES_TIME
发送时间请求以检索该数据包和RETRIEVAL_TIME
(现在数据包实际到达的时间) ) 和REQUEST_ID
(REQUEST_TYPE
警报、数据、通知等)。 - 现在,这个线程(一个无限循环)将带有新标头的数据包放入环形缓冲区,然后通知其他线程(线程#2)解析此信息。
- 在线程 #2 中,当收到通知时,它会锁定缓冲区并读取弹出数据包并开始解析它。
- 每条消息都包含一些用户可能不感兴趣的信息,因此我提供了用户回调方法来处理对用户有用的数据。
基本上,我在线程 2 中做这样的事情:-
线程#2
wait(data_put_in_buffer_cond)
lock(buffer_mutex)
packet_t* packet = pop_packet_from_buffer(buf);
unlock(buffer_mutex)
/* parsing the package... */
parsed_packet_t* parsed_packet = parse_and_change_endianess(packet->data);
/* header for put by thread #1 with host byte order only not parsing necessary */
header_t* header = get_header(packet);
/* thread 1 sets free callback for kind of packet it puts in buffer
* This not a critical section section of buffer, so fine without locks
*/
buffer.free_callback(packet);
foreach attribute in parsed_packet->attribute_list {
register_info_t* rinfo = USER_REGISTRED_EVENT_TABLE[header->device_id][attribute.attr_id];
/*user is register with this attribute ID on this device ID */
if(rinfo != NULL) {
rinof->callback(packet);
}
// Do some other stuff with this attribute..
}
free(parsed_packet);
现在,我担心的是,如果用户实现的回调函数需要一些时间才能完成,同时我可能会因为环形缓冲区处于覆盖模式而丢弃一些数据包,会发生什么?我已经为 3 到 4 台设备测试了我的 API,如果回调函数等待相当长的时间,我看不到太多丢弃事件。我推测这种方法可能不是最好的。
如果我使用某种线程池来运行用户回调函数,它会是一个更好的设计吗?在那种情况下,我需要在将数据包发送给用户回调之前对其进行显式复制?每个数据包大约 500 到 700 字节,我每秒从每个设备收到大约 2 个数据包。任何有关改进当前设计或解决此问题的建议或意见将不胜感激。