简体   繁体   English

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

[英]Suggestion for callbacks oriented library in C

I'm making small library for controlling various embedded devices using C language. 我正在使用C语言控制各种嵌入式设备的小型库。 I'm using UDP sockets to communicate with each of the devices. 我正在使用UDP套接字与每个设备进行通信。 Devices send me various interesting data, alarms and notifications and at the same time they send some data that is used internally by the library but may not be interesting to users. 设备向我发送各种有趣的数据,警报和通知,同时它们发送一些由库内部使用的数据,但可能对用户不感兴趣。 So, I've implemented a callback approach, where user could register a callback function with some interesting events on each of the devices. 所以,我实现了一种回调方法,用户可以在每个设备上注册回调函数和一些有趣的事件。 Right now, overall design of this library is something like this:- 现在,这个库的整体设计是这样的: -

  • I've two threads running. 我有两个线程在运行。
  • In one of the thread, there is a infinite while event-loop that uses select and non-blocking sockets to maintain the communication with each of the devices. 在其中一个线程中,有一个无限while事件循环,它使用selectnon-blocking sockets来维护与每个设备的通信。
  • Basically, every time I receive a packet from any of devices, I strip off the header which is 20 bytes of some useless information and add my own header containing DEVICE_ID , REQUES_TIME (time request was sent to retrieve that packet and RETRIEVAL_TIME (time now when packet actually arrived) and REQUEST_ID and REQUEST_TYPE (alarm, data, notification etc..). 基本上,每次我从任何设备收到一个数据包时,我都会删除20个字节的一些无用信息的标头,并添加我自己的包含DEVICE_IDREQUES_TIME的标头(发送时间请求以检索该数据包和RETRIEVAL_TIME (现在是时候了)数据包实际到达)和REQUEST_IDREQUEST_TYPE (警报,数据,通知等..)。
  • Now, this thread (one with infinite loop) put packet with new header into ring buffer and then notifies other thread (thread #2) to parse this information. 现在,这个线程(一个具有无限循环)将带有新头的数据包放入环形缓冲区,然后通知其他线程(线程#2)解析此信息。
  • In thread #2, when notification is received, it locks the buffer and read pop the packet and start parsing it. 在线程#2中,当收到通知时,它会锁定缓冲区并读取弹出数据包并开始解析它。
  • Every message contains some information that user may not be interested, so I'm providing user call back approach to act upon data which is useful to user. 每条消息都包含一些用户可能不感兴趣的信息,因此我提供用户回调方法来处理对用户有用的数据。

Basically, I'm doing something like this in thread 2:- 基本上,我在线程2中做了类似的事情: -

THREAD #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);

Now, my concerned is that what will happen if callback function that user implements takes some time to complete and meanwhile I may drop some packet because ring buffer is in overwriting mode? 现在,我担心的是,如果用户实现的回调函数需要一些时间才能完成,同时我可能会丢弃一些数据包,因为环形缓冲区处于覆盖模式? I've tested my API for 3 to 4 devices, I don't see much drop event if callback function wait decent amount of time..I'm speculating that this approach may not be best. 我已经测试了我的3到4个设备的API,如果回调函数等待合适的时间,我没有看到太多丢弃事件。我猜测这种方法可能不是最好的。

Would it be a better design, if I use some sort of thread-pool to run user callback functions? 如果我使用某种线程池来运行用户回调函数,它会是一个更好的设计吗? In that case I would need to make explicit copy of packet before I send it to user callback? 在那种情况下,我需要在将数据包发送给用户回调之前制作显式的数据包副本? Each packet is about 500 to 700 bytes, I get around 2 packets per second from each device. 每个数据包大约有500到700个字节,每个设备每秒大约可以获得2个数据包。 Any suggestions or comments on improving the current design or solving this issues would be appreciated. 任何有关改进当前设计或解决此问题的建议或意见将不胜感激。

Getting 500-700 bytes per device is not a problem at all, especially if you only have 3-4 devices. 每台设备获得500-700字节根本不是问题,特别是如果您只有3-4台设备。 Even if you had, let's say, 100 devices, it should not be a problem. 即使你有100个设备,也不应该是一个问题。 The copy overhead would be most probably negligible. 复制开销很可能是微不足道的。 So, my suggest would be: do not try to optimize beforehand until you are certain that buffer copying is your bottleneck. 所以,我的建议是:在你确定缓冲区复制是你的瓶颈之前,不要先尝试优化。

About losing packets, as you say in your question, you are already using a buffer ring (I assume that is something like a circular queue, right?). 关于丢失数据包,正如你在问题中所说的那样,你已经在使用缓冲环(我认为它就像一个循环队列,对吧?)。 If the queue becomes full, then you just need to make thread #1 to wait until there is some available space in the queue. 如果队列已满,那么您只需要使线程#1等待,直到队列中有可用空间为止。 Clearly, more events from different devices may arrive, but that should not be a problem. 显然,来自不同设备的更多事件可能会到来,但这应该不是问题。 Once, you have space again, select will let you know that you have available data from different devices, so you will just need to process all that data. 一旦您再次拥有空间, select会告诉您有来自不同设备的可用数据,因此您只需要处理所有数据。 Of course, in order to have a balanced system, you can set the size of the queue to a value that reduces as much as possible the number of times that the queue is full, and thus, thread #1 needs to wait. 当然,为了拥有一个平衡的系统,您可以将队列的大小设置为尽可能减少队列已满的次数的值,因此,线程#1需要等待。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM