传输数据 to/from 回调 from/to 工作线程

Transferring data to/from a callback from/to a worker thread

我当前的应用程序是一个用 C 编写的玩具 Web 服务,旨在复制 http://sprunge.us/ 的行为(通过 http POST 获取数据,将其存储到磁盘,returns客户端对数据的 url - 还提供先前根据请求存储的数据)。

应用程序的结构使得线程池用工作线程(只是一个采用 void* 参数的函数指针)实例化,并打开一个套接字以侦听传入连接。该程序的主循环包括一个 sock = accept(...) 调用,然后是一个 pool_add_task(worker_function_parse_http, sock) 以快速处理请求。 parse_http 工作人员解析传入请求,然后将另一个任务添加到工作队列以存储数据 (POST) 或提供先前存储的数据 (GET)。

我对这种方法的问题源于使用 http-parser 库,该库使用回调设计来 return 解析数据(我看过的所有 http 解析器都使用这种样式)。我遇到的问题是这样的:

我的 parse_http 工人:

  1. 从接受的套接字中缓冲数据(函数的唯一参数,在这个阶段)
  2. 根据其 API 设置一个 http-parser 对象,完成设置回调函数,以便在它完成解析 URL 或 BODY 或任何。 (这些函数是由 http-parser lib 定义的固定类型签名,带有指向包含与调用相关的已解析数据的缓冲区的指针,因此我无法传入自己的变量并以这种方式解决问题. 这些函数还 return 一个 http 解析器的状态代码,所以我也不能使用 return 值。从解析器中获取数据供以后使用的建议方法是将其复制出来在回调期间到一个全局变量 - 多线程的乐趣。)

  3. 对缓冲的套接字数据执行解析器。在此阶段,解析器在解析缓冲区的不同部分时应调用其设置回调。回调提供了与每个回调相关的解析数据(例如,提供给 body_parsed 回调函数的 BODY 段)。

  4. 嗯,问题就出在这里。解析器已执行,但我无权访问已解析的数据。在这里,我将使用工作函数向队列添加一个新任务以存储接收到的正文数据或另一个任务以处理对先前存储的数据的 GET 请求。这些函数需要提供已解析的信息(POST 数据或 GET url)以及已接受的套接字,以便现在委托的工作可以响应请求并关闭连接。

当然,解决这个问题的明显方法就是不使用异步实践的线程池模型,但我想知道,现在和以后,如何最好地解决这个问题。

如何将这些回调中的解析数据返回给工作线程函数。我考虑过让我的 on_url_parsedon_body_parsed 完成应用程序的其余工作(存储和检索数据),但当然我不再有客户端套接字在这些上下文中响应。

如果需要,我可以在有机会时post上传项目的源代码。

编辑:事实证明,可以从这个特定的 http-parser 库的回调中访问用户定义的 void *,因为回调被传递给调用者(解析器对象)的引用它有一个用户可定义的数据字段。

一个设计良好的回调接口可以让你给解析器一个 void * ,它会在调用它们时传递给每个回调函数。您提供的回调函数知道它指向什么类型的对象(因为您同时提供了数据指针和函数指针),因此它们可以强制转换并正确取消引用它。除了其他优点之外,您还可以通过这种方式让回调访问启动解析的函数的局部变量,而不必依赖全局变量。

如果您使用的解析器库没有这样的功能(并且您不想切换到设计更好的解析器库),那么您可能可以使用线程局部存储而不是全局变量。具体怎么做取决于您的线程库和编译器,或者您可以通过使用线程标识符作为某些全局数据结构(例如散列 table)中特定于线程的槽的键来滚动您自己的线程库和编译器。