C语言中面向回调的库的建议

时间:2012-05-28 08:01:20

标签: c sockets

我正在制作用于使用C语言控制各种嵌入式设备的小型库。我正在使用UDP套接字与每个设备进行通信。设备向我发送各种有趣的数据,警报和通知,同时它们发送一些由库内部使用的数据,但可能对用户不感兴趣。所以,我实现了一种回调方法,用户可以在每个设备上注册回调函数和一些有趣的事件。现在,这个库的整体设计是这样的: -

  • 我有两个线程正在运行。
  • 在其中一个主题中,有一个无限while事件循环,它使用selectnon-blocking sockets来维护与每个设备的通信。
  • 基本上,每当我从任何设备收到数据包时,我都会删除一些20字节的无用信息标题,并添加我自己的包含DEVICE_IDREQUES_TIME的标题(时间请求为发送以检索该数据包和RETRIEVAL_TIME(数据包实际到达的时间)和REQUEST_ID以及REQUEST_TYPE(警报,数据,通知等)。
  • 现在,这个线程(一个带有无限循环的线程)将带有新头的数据包放入环形缓冲区,然后通知其他线程(线程#2)解析此信息。
  • 在线程#2中,当收到通知时,它会锁定缓冲区并读取弹出数据包并开始解析它。
  • 每条消息都包含一些用户可能不感兴趣的信息,因此我提供用户回调方法来处理对用户有用的数据。

基本上,我在主题2中做了类似的事情: -

THREAD#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个数据包。任何有关改进当前设计或解决此问题的建议或意见将不胜感激。

1 个答案:

答案 0 :(得分:1)

每台设备获得500-700字节根本不是问题,特别是如果您只有3-4台设备。即使你有100个设备,也不应该是一个问题。复制开销很可能是微不足道的。所以,我的建议是:在你确定缓冲区复制是你的瓶颈之前,不要先尝试优化。

关于丢失数据包,正如您在问题中所说,您已经在使用缓冲环(我假设它类似于循环队列,对吧?)。如果队列已满,那么您只需要使线程#1等待,直到队列中有可用空间为止。显然,来自不同设备的更多事件可能会到来,但这应该不是问题。一旦您再次拥有空间,select将告知您有来自不同设备的可用数据,因此您只需要处理所有数据。当然,为了拥有一个平衡的系统,您可以将队列的大小设置为尽可能减少队列已满的次数的值,因此,线程#1需要等待。