2010-06-16 8 views
5

Existe-t-il des verrous dans Linux où la file d'attente est FIFO? Cela semble une chose tellement évidente, et pourtant je viens de découvrir que les mutex pthread ne sont pas des FIFO, et les sémaphores ne sont pas non plus des FIFO (je travaille sur le noyau 2.4) ...Synchronisation Linux avec file d'attente FIFO

avoir un verrou avec file d'attente FIFO, ou existe-t-il un moyen facile de faire un avec les mécanismes existants?

Répondre

3

Voici un moyen de créer un "ticket de verrouillage" simple, basé sur des primitives pthreads. Il devrait vous donner quelques idées:

#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

Si vous demandez ce que je pense que vous demandez la réponse courte est non. Les threads/processus sont contrôlés par le planificateur du système d'exploitation. Un thread aléatoire va obtenir le verrou, les autres ne le sont pas. Eh bien, potentiellement plus d'un si vous utilisez un sémaphore de comptage, mais ce n'est probablement pas ce que vous demandez.

Vous voudrez peut-être regarder pthread_setschedparam mais cela ne vous mènera pas là où je soupçonne que vous voulez aller.

Vous pourriez probablement écrire quelque chose mais je soupçonne qu'il finira par être inefficace et par vaincre en utilisant des threads en premier lieu puisque vous finirez par céder au hasard chaque thread jusqu'à ce que celui que vous voulez obtienne le contrôle.

Les chances sont bonnes que vous ne faites que penser au problème de la mauvaise façon. Vous pourriez décrire votre objectif et obtenir de meilleures suggestions.

+0

Je suis en présence d'une situation serveur-client et le serveur doit conserver un fichier journal de manière à ne pas interférer avec ses E/S, ce qui signifie qu'un thread de connexion serveur-clent ne peut pas attendre car il attend pour un mutex pour l'échec du journal qu'un autre thread de ce type s'est bloqué. Je pensais à lancer chaque entrée dans un thread séparé "write to logfile" qui peut aller attendre sans interférer avec son fil parent. Les messages dans le fichier journal peuvent être mélangés , mais doivent maintenir une chronologie correcte par connexion, c'est pourquoi j'ai besoin d'une FIFO. – EpsilonVector

+1

Configurer une file d'attente. Les connexions c-s écrivent leurs informations de journal dans la file d'attente.Un thread distinct lit la file d'attente et écrit dans le fichier. Vous devez encore acquérir un verrou sur la file d'attente, mais à moins que vous ne le sachiez, cela ne devrait pas être pertinent. La durée d'acquisition du verrou de la file d'attente sera éclipsée par la lenteur relative des fichiers et des E/S réseau. Puisque n'importe quel thread c-s écrit dans la file d'attente pour que votre sortie de journal soit également en ordre par thread. – Duck

+0

Ouais c'est ce que je voulais éviter de faire (cela nécessiterait plus de changements qu'un verrou FIFIO), mais je suppose que je n'ai plus le choix ... – EpsilonVector

0

J'ai eu une exigence similaire récemment, sauf pour faire face à plusieurs processus. Voici ce que je trouve:

  • Si vous avez besoin de commande FIFO 100% correct, aller avec pthread ticket lock de café. Si vous êtes satisfait de 99% et privilégiez la simplicité, un sémaphore ou un mutex peut vraiment très bien fonctionner.

verrouillage du billet peut être fait pour travailler dans les processus:
Vous devez utiliser la mémoire partagée, mutex processus partagé et variable de condition, gérer les processus qui meurent avec le mutex verrouillé (-> mutex robuste) ... Ce qui est un peu exagéré ici, tout ce dont j'ai besoin, c'est que les différentes instances ne soient pas programmées en même temps et que l'ordre soit plutôt juste.

L'utilisation d'un sémaphores:

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 */ 
} 

La commande est FIFO presque 100%.

Note: Ceci est avec un noyau Linux 4.4, 2.4 peut être différent.

Questions connexes