代码之家  ›  专栏  ›  技术社区  ›  Edward

C中的多个编写器线程安全队列

  •  13
  • Edward  · 技术社区  · 16 年前

    我正在使用pthreads开发多线程C应用程序。我有一个线程写入一个数据库(数据库库只在一个线程中使用是安全的),还有几个线程正在收集数据并进行处理,然后需要将结果发送到数据库线程进行存储。我在上文中看到,在C中创建多个编写器安全队列是“可能的”,但是我看到的每个地方都简单地说,对于这个示例来说,它“太复杂了”,并且只演示了一个编写器安全队列。

    我需要以下东西:

    • 有效插入和移除。我假设像其他队列O(1)一样,排队和退排队是可能的。
    • 动态分配的内存,即链接结构。我不需要对队列的大小有任意限制,所以数组实际上不是我要找的。

    编辑: 读取线程不应该在空队列上旋转,因为可能有几分钟的时间没有写操作,有大量的短时间的写操作。

    4 回复  |  直到 14 年前
        1
  •  16
  •   Steve Jessop    16 年前

    当然,这里有没有锁的队列。不过,根据您在评论中所说的,这里的性能一点也不重要,因为您无论如何都要为每次写入创建一个线程。

    所以,这是一个条件变量的标准用例。使自己成为一个包含互斥体、条件变量、链接列表(或者循环缓冲区(如果愿意))和取消标志的结构:

    write:
        lock the mutex
        (optionally - check the cancel flag to prevent leaks of stuff on the list)
        add the event to the list
        signal the condition variable
        unlock the mutex
    
    read:
       lock the mutex
       while (list is empty AND cancel is false):
           wait on the condition variable with the mutex
       if cancel is false:  // or "if list non-empty", depending on cancel semantics
           remove an event from the list
       unlock the mutex
       return event if we have one, else NULL meaning "cancelled"
    
    cancel:
       lock the mutex
       set the cancel flag
       (optionally - dispose of anything on the list, since the reader will quit)
       signal the condition variable
       unlock the mutex
    

    如果您使用的是一个带有外部节点的列表,那么您可能需要在互斥锁之外分配内存,只是为了减少它的保留时间。但是,如果您使用一个可能最简单的侵入式列表节点设计事件。

    编辑:如果在“取消”中,您将“信号”更改为“广播”,您还可以支持多个读卡器(没有便携式保证,其中一个获得给定事件)。虽然你不需要它,但它也不需要任何东西。

        2
  •  5
  •   Fire Lancer    16 年前

    如果您不需要无锁队列,那么您可以用一个锁来结束现有的队列。

    Mutex myQueueLock;
    Queue myQueue; 
    void mtQueuePush(int value)
    {
        lock(myQueueLock);
        queuePush(myQueue, value);
        unlock(myQueueLock);
    }
    int mtQueueNext()
    {
        lock(myQueueLock);
        int value = queueFront(myQueue);
        queuePop(myQueue);
        unlock(myQueueLock);
        return value;
    }
    

    之后唯一的事情就是在队列为空时为mtqueueNext添加某种处理。

    编辑: 如果您有一个读卡器、一个编写器无锁队列,那么您只需要在mtqueuepush周围有一个锁,以防止多个同时编写器。

    有一个读写器无锁队列的NUBMER,但大多数都是以C++模板类实现的。然而,做一个谷歌搜索,如果需要的话,要想办法用普通的C语言重写它们。

        3
  •  4
  •   user82238    14 年前

    http://www.liblfds.org

    用C语言编写的无锁数据结构库。

    有M&S队列。

        4
  •  1
  •   Community Mohan Dere    9 年前

    我将使用多个单个编写器队列(每个编写器线程一个)。然后你可以查一下 this 如何让单个读卡器读取各种队列。