多线程avahi解决导致段错误

时间:2013-01-21 00:21:16

标签: bonjour dbus zeroconf avahi

我正在尝试将支持zeronconf的C / C ++应用程序移植到Linux,但是我正在获得与D-BUS相关的段错误。我不确定这是否是Avahi中的错误,我滥用Avahi或我的代码中的错误。

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

这个整个过程在同步完成时效果很好但是失败了 当多个ZeroconfResolvers同时使用时,会出现段错误 时间异步(即我有多个线程创建自己的 ZeroconfResolver对象)。一个微不足道的适应对象 再现segfaults可以在下面的代码中看到(可能不会产生一个 立即发生了段错,但在我的用例中经常发生这种情况。)

我明白“开箱即用”Avahi不是线程安全的,但是 根据我对[1]的解释,有多个是安全的 AvahiClient / AvahiPoll在同一过程中对象,只要它们是 没有从多个线程“访问”。每个ZeroconfResolver都有 它自己的一组Avahi对象,它们之间不会相互影响 跨线程边界。

段错误发生在Avahi中看似随机的函数中 图书馆。一般来说,它们发生在avahi_client_new或 avahi_service_resolver_new函数引用dbus。是Avahi维基 意味着暗示AvahiClient / AvahiPoll对象的“创造”是 也不是线程安全吗?

[1] http://avahi.org/wiki/RunningAvahiClientAsThread

#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;
}

1 个答案:

答案 0 :(得分:0)

一个似乎工作正常的解决方案是在avahi_client_new,avahi_service_resolver_new和相应的自由操作周围添加自己的同步(常见的互斥锁)。似乎avahi并未声称这些操作是内部同步的。

声称独立对象不会干扰。

我使用这种方法取得了成功,使用了一个带有静态互斥锁的辅助类。具体来说,这是一个静态成员函数(或自由函数):

std::mutex& avahi_mutex(){
  static std::mutex mtx;
  return mtx;
}

并锁定代码的任何部分(尽可能小)执行free或new:

{
  std::unique_lock<std::mutex> alock(avahi_mutex());
  simple_poll = avahi_simple_poll_new()
}