首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >curl_multi_remove_handle的线程安全

curl_multi_remove_handle的线程安全
EN

Stack Overflow用户
提问于 2019-05-15 07:24:09
回答 2查看 656关注 0票数 1

似乎有些消息来源建议使用curl_multi_remove_handle来“使”卷发句柄失效,并使curl_multi_wait尽早返回。这似乎不在线程安全保证范围之内(如果是从另一个线程执行的话),还是我错了(线程安全保证基本上只是重入保证)?

建议的信号curl_multi_wait提前返回的方式是什么?它真的需要通过超时来完成吗?(在Linux下,我将使用epoll设置中的event fd来有效地使“等待这些套接字或此事件fd或给定的超时”)。我似乎可以使用自定义的curl_waitfd结构,但这需要为虚拟套接字设置特定于平台的设置。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-05-15 22:20:13

如果的句柄运行在线程A中,则不能从线程B调用curl_multi_remove_handle,这只会导致眼泪和痛苦。

您可以选择,例如:

  • 用户对curl_multi_wait()的超时时间足够短,因此您不需要中止它
  • 添加私有套接字/文件描述符,以便在需要时将数据发送到中止。
  • 从需要停止的传输的进度回调(或另一个回调)返回错误--通过设置他们都检查的标志(全局的或全局的)
  • 重新修改你的应用程序逻辑,这样你就可以考虑在没有停止的情况下,把它转移到“死”状态,并且有它的原因,并在稍后关闭它,在你决定忽略它之后,你不需要太在意它被做了什么。

curl_multi_poll()

在我第一次写了这个答案之后,我们在libcurl中引入了民意测验。这个函数非常类似于curl_multi_wait,但也允许它先发制人地使用唤醒返回,从而为应用程序提供了更多的替代方法。

票数 2
EN

Stack Overflow用户

发布于 2021-11-16 05:33:48

不幸的是,curl_multi并不是,现在人们所认为的“线程安全”。是的,您可以在两个不同的线程中使用CURLM句柄,只要它们不同时访问它。但是,对于C或C++中的几乎任何数据结构,这都是正确的。

因此,如果有一个线程使用curl_multi_wait()运行事件循环,则不能使用第二个线程通过curl_multi_add_handle()添加新作业或通过curl_multi_remove_handle()删除作业。嗯,它在大多数情况下都能工作,但特别是在高负载期间,由于并发访问libcurl的内部数据结构,您将开始获取数据损坏和分段错误。

有两种方法可以解决这个问题,但都需要编写一些代码:

  • 使用较新的curl_multi_poll()接口,它(与curl_multi_wait()不同)可以通过curl_multi_wakeup()进行外部中断。是的,curl_multi_wakeup()CURLM句柄上的唯一函数,可以安全地从另一个线程(甚至多个线程)并发调用。要向事件循环添加新请求或从事件循环中删除请求,您需要一些请求队列和一个互斥锁,以确保对该队列的访问。然后,要添加一个新工作,您可以这样做:
代码语言:javascript
运行
复制
- (thread 1 is running `curl_multi_poll()` in an endless loop)
- thread 2 acquires said mutex
- thread 2 posts an "add easy handle request" into the request queue
- thread 2 releases said mutex again
- thread 2 calls `curl_multi_wakeup()`
- thread 1 acquires the mutex after `curl_multi_poll()` returns
- thread 1 then processes the "add easy handle request" in the job list and performs `curl_multi_add_handle()`
- thread 1 then releases the mutex again
- thread 1 does all other necessary work (in particular call `curl_multi_perform()` and pass finished transfers to the application etc.)
- thread 1 calls `curl_multi_poll()` again

要删除作业,您可以使用相同的过程,让线程2向请求队列发布“删除轻松句柄请求”,而不是“添加轻松句柄请求”,然后让线程1调用curl_multi_remove_handle()而不是curl_multi_add_handle()

在此解决方案中,对CURLM句柄的所有调用都是从线程1执行的,唯一的例外是curl_multi_wakeup(),其他线程使用它来向线程1发出在请求队列中等待的新工作的信号。

  • 或者使用curl_action()接口,您必须为libcurl提供两个回调,其中libcurl报告要查看的文件描述符和应用程序的超时。然后,您必须亲自调用epoll()或类似的OS函数,以等待事件循环线程中的活动(或超时)。然后再添加一个互斥锁,以序列化对CURLM句柄的访问:您的事件循环线程应该在它调用curl_action() (或CURLM句柄上的任何其他函数)之前锁定该互斥锁,然后立即解锁它。由于curl_action() (不像curl_multi_poll())不睡觉,所以这个互斥锁只会在短时间内锁定。因此,其他线程也可以轻松地直接锁定互斥对象,并根据需要调用curl_multi_add_handle()curl_multi_remove_handle()。但是,请注意,这些干预的句柄的添加或删除可以修改活动FD集,您可能需要与事件循环线程进行一些同步,以通知它修改后的epoll()集。

第一个解决方案可能更容易实现。您应该能够在Github上为这两个变体找到libcurl包装器,但在任何关键应用程序中使用它们之前,一定要对它们进行深入的测试。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56143716

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档