首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多线程avahi解析导致段错误

多线程avahi解析导致段错误
EN

Stack Overflow用户
提问于 2013-01-21 08:21:16
回答 1查看 1.4K关注 0票数 1

我正在尝试将我的支持zeronconf的C/C++应用程序移植到Linux上,但是我得到了与D-BUS相关的段错误。我不确定这是Avahi中的一个bug,还是我对Avahi的误用,还是我代码中的一个bug。

我使用的是一个封装了AvahiClient、AvahiSimplePoll和AvahiServiceResolver的ZeroconfResolver对象。ZeroconfResolver有一个Resolve函数,它首先实例化AvahiSimplePoll,然后实例化AvahiClient,最后实例化AvahiServiceResolver。在每次实例化时,我都会在继续下一次实例化之前检查错误。在成功创建AvahiServiceResolver之后,它使用AvahiSimplePoll调用avahi_simple_poll_loop。

当同步完成时,整个过程工作得很好,但当同时异步使用多个ZeroconfResolvers时(即,我有多个线程创建自己的ZeroconfResolver对象),则会出现段错误。在下面的代码中可以看到对对象的一个简单的调整,该对象重现了段错误(可能不会立即产生段错误,但在我的用例中它经常发生)。

我知道“开箱即用”的Avahi不是线程安全的,但根据我对1的解释,在同一进程中有多个AvahiClient/AvahiPoll对象是安全的,只要它们不被多个线程“访问”。每个ZeroconfResolver都有自己的一组Avahi对象,这些对象不会跨线程边界相互交互。

段错误出现在Avahi库中看似随机的函数中。通常,它们发生在引用dbus的avahi_client_new或avahi_service_resolver_new函数中。Avahi wiki是否意味着AvahiClient/AvahiPoll对象的“创建”也不是线程安全的?

1

代码语言:javascript
复制
#include <dispatch/dispatch.h>
#include <cstdio>

#include <sys/types.h>
#include <netinet/in.h>

#include <avahi-client/lookup.h>
#include <avahi-client/client.h>
#include <avahi-client/publish.h>
#include <avahi-common/alternative.h>
#include <avahi-common/simple-watch.h>
#include <avahi-common/malloc.h>
#include <avahi-common/error.h>
#include <avahi-common/timeval.h>

void resolve_reply(
  AvahiServiceResolver *r,
  AVAHI_GCC_UNUSED AvahiIfIndex interface,
  AVAHI_GCC_UNUSED AvahiProtocol protocol,
  AvahiResolverEvent event,
  const char *name,
  const char *type,
  const char *domain,
  const char *host_name,
  const AvahiAddress *address,
  uint16_t port,
  AvahiStringList *txt,
  AvahiLookupResultFlags flags,
  void * context) {

    assert(r);

    if (event == AVAHI_RESOLVER_FOUND)
      printf("resolve_reply(%s, %s, %s, %s)[FOUND]\n", name, type, domain, host_name);

    avahi_service_resolver_free(r);
    avahi_simple_poll_quit((AvahiSimplePoll*)context);
}


int main() {
  // Run until segfault
  while (true) {
    // Adding block to conccurent GCD queue (managed thread pool)
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), [=]{
      char name[] = "SomeHTTPServerToResolve";
      char domain[] = "local.";
      char type[] = "_http._tcp.";

      AvahiSimplePoll * simple_poll = NULL;
      if ((simple_poll = avahi_simple_poll_new())) {
        int error;
        AvahiClient * client = NULL;
        if ((client = avahi_client_new(avahi_simple_poll_get(simple_poll),   AVAHI_CLIENT_NO_FAIL, NULL, NULL, &error))) {
          AvahiServiceResolver * resolver = NULL;
             if ((resolver = avahi_service_resolver_new(client, AVAHI_IF_UNSPEC,     AVAHI_PROTO_UNSPEC, name, type, domain, AVAHI_PROTO_UNSPEC, AVAHI_LOOKUP_NO_ADDRESS,     (AvahiServiceResolverCallback)resolve_reply, simple_poll))) {
               avahi_simple_poll_loop(simple_poll);
               printf("Exit Loop(%p)\n", simple_poll);
             } else {
               printf("Resolve(%s, %s, %s)[%s]\n", name, type, domain, avahi_strerror(avahi_client_errno(client)));
             }
             avahi_client_free(client);
        } else {
          printf("avahi_client_new()[%s]\n", avahi_strerror(error));
        }
        avahi_simple_poll_free(simple_poll);
      } else {
        printf("avahi_simple_poll_new()[Failed]\n");
      }
    });
  }

  // Never reached
  return 0;
}
EN

回答 1

Stack Overflow用户

发布于 2013-04-06 15:41:22

一个不错的解决方案是在avahi_client_new、avahi_service_resolver_new和相应的空闲操作周围添加您自己的同步(一个公共互斥)。看起来avahi并没有声称这些操作是内部同步的。

所声称的是独立的对象不干涉。

我成功地使用了这种方法,使用了一个带有静态互斥锁的helper类。具体地说,静态成员函数(或自由函数)如下:

代码语言:javascript
复制
std::mutex& avahi_mutex(){
  static std::mutex mtx;
  return mtx;
}

在任何(尽可能小的)代码段周围设置一个锁,执行免费的或新的操作:

代码语言:javascript
复制
{
  std::unique_lock<std::mutex> alock(avahi_mutex());
  simple_poll = avahi_simple_poll_new()
}    
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14430906

复制
相关文章

相似问题

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