3

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

  • 我有两个线程正在运行。
  • 在其中一个线程中,有一个无限while事件循环,它使用selectnon-blocking sockets保持与每个设备的通信。
  • 基本上,每次我从任何设备收到一个数据包时,我都会去掉一些无用信息的 20 个字节的标头,并添加我自己的标头,其中包含DEVICE_IDREQUES_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 个数据包。任何有关改进当前设计或解决此问题的建议或意见将不胜感激。

4

1 回答 1

1

每个设备获得 500-700 字节根本不是问题,尤其是在您只有 3-4 个设备的情况下。即使您拥有 100 台设备,也应该不是问题。复制开销很可能可以忽略不计。因此,我的建议是:在确定缓冲区复制是您的瓶颈之前,不要尝试预先优化。

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

于 2012-05-28T09:30:39.247 回答