2010-06-16 50 views
5

Linux中等待队列为FIFO时是否存在锁定?这似乎是这样一个明显的事情,但我刚刚发现,pthread互斥体不是FIFO,信号量显然也不是FIFO(我正在研究内核2.4(作业))...使用FIFO等待队列的Linux同步

Linux与FIFO等待队列锁定,还是有一个简单的方法来使现有的机制之一?

回答

3

下面是创建一个简单的排队“票锁”,建立在并行线程原语的方式。它应该给你一些想法:

#include <pthread.h> 

typedef struct ticket_lock { 
    pthread_cond_t cond; 
    pthread_mutex_t mutex; 
    unsigned long queue_head, queue_tail; 
} ticket_lock_t; 

#define TICKET_LOCK_INITIALIZER { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER } 

void ticket_lock(ticket_lock_t *ticket) 
{ 
    unsigned long queue_me; 

    pthread_mutex_lock(&ticket->mutex); 
    queue_me = ticket->queue_tail++; 
    while (queue_me != ticket->queue_head) 
    { 
     pthread_cond_wait(&ticket->cond, &ticket->mutex); 
    } 
    pthread_mutex_unlock(&ticket->mutex); 
} 

void ticket_unlock(ticket_lock_t *ticket) 
{ 
    pthread_mutex_lock(&ticket->mutex); 
    ticket->queue_head++; 
    pthread_cond_broadcast(&ticket->cond); 
    pthread_mutex_unlock(&ticket->mutex); 
} 
4

如果你问我在想什么,你问的简短答案是否定的。线程/进程由OS调度程序控制。一个随机线程将获得锁定,其他则不会。那么,如果你正在使用计数信号量,可能会多于一个,但这可能不是你要求的。

你可能想看看pthread_setschedparam,但它不会让你,我怀疑你想去的地方。

你也许可以写的东西,但我怀疑它最终会被低效和破坏使用摆在首位的线程,因为你最终只会随机产生的每个线程,直到你想要的得到控制。

机会是很好的,你只是想在错误的道路的问题。你可能想描述你的目标,并得到更好的建议。

+0

我有一个服务器 - 客户端的情况怎么回事,服务器需要保持一个日志文件中,以便写入它不会干扰方式的I/O,这意味着服务器克伦特连接线程不能去等待因为它正在等待 为另一个此类线程锁定的日志失败的互斥体。我正在考虑将每个条目扔进一个单独的“写入日志文件”线程,该线程可以等待而不会干扰其父线程。日志文件中的消息可以混合使用,但必须保持每个连接的正确时间顺序,这就是为什么我需要FIFO。 – EpsilonVector 2010-06-16 12:43:07

+1

设置一个队列。 c-s连接将其日志信息写入队列。一个单独的线程读取队列并写入文件。你仍然必须获得队列上的锁定,但除非你知道否则这应该是无关紧要的。获取队列锁定的时间量将因文件和网络I/O的相对缓慢而变得相形见绌。由于任何给定的c-s线程正在写入队列,以便您的日志输出同样按每个线程的顺序排列。 – Duck 2010-06-16 20:17:21

+0

是的,这是我想避免做的事情(需要比FIFIO锁更多的变化),但我想我没有选择了... – EpsilonVector 2010-06-16 20:42:30

0

我最近有一个类似的要求,除了处理多个进程。这里是我的发现:

  • 如果你需要100%正确的FIFO排序,去咖啡馆的pthread ticket lock

  • 如果你对99%满意并喜欢简单性,信号量或互斥量实际上可以做得非常好。

票务锁可以进行跨进程的工作:
您需要使用共享内存,进程共享的互斥和条件变量,处理与锁定互斥死亡过程( - >强大的互斥体)...这在这里有点矫枉过正,我需要的只是不同的实例不能同时安排,而且命令大多是公平的。

使用旗语:

static sem_t *sem = NULL; 

void fifo_init() 
{ 
    sem = sem_open("/server_fifo", O_CREAT, 0600, 1); 
    if (sem == SEM_FAILED) fail("sem_open"); 
} 

void fifo_lock() 
{ 
    int r; 
    struct timespec ts; 
    if (clock_gettime(CLOCK_REALTIME, &ts) == -1) fail("clock_gettime"); 
    ts.tv_sec += 5;  /* 5s timeout */ 

    while ((r = sem_timedwait(sem, &ts)) == -1 && errno == EINTR) 
     continue;  /* Restart if interrupted */ 
    if (r == 0) return; 

    if (errno == ETIMEDOUT) fprintf(stderr, "timeout ...\n"); 
    else     fail("sem_timedwait"); 
} 

void fifo_unlock() 
{ 
    /* If we somehow end up with more than one token, don't increment the semaphore... */ 
    int val; 
    if (sem_getvalue(sem, &val) == 0 && val <= 0) 
     if (sem_post(sem)) fail("sem_post"); 
    usleep(1); /* Yield to other processes */ 
} 

排序几乎是100%FIFO。

注:这是一个4.4的Linux内核,2.4可能会有所不同。