Bonjour tout le monde,

Je coince sur un comportement étrange de sémaphores POSIX (semaphore.h). À un moment une sémaphore (queue3->full plus bas) est en wait. Et je fais un post sur une autre sémaphore (queue1->mutex plus bas). Et ce post-là déclenche le wait de la sémaphore queue3->full !

J'ai pu isoler ce comportement en traçant tous mes appels à sem_wait et sem_post avec des #define :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifdef SQ_DEBUG
#  define sq_debug(msg...)   { if (queue->debugged) \
        { \
            fprintf(stderr, "sq %d", queue->debugged); \
            debugmsg("", msg); \
        } }
 
#  define sem_post(sem) \
        { \
            sq_debug("post to " #sem " (%p) at line %d", sem, __LINE__); \
            sem_post(sem); \
        }
#  define sem_wait(sem) \
        { \
            sq_debug("wait for " #sem " (%p) at line %d", sem, __LINE__); \
            sem_wait(sem); \
            sq_debug("wait done for " #sem " (%p) at line %d", sem, __LINE__); \
        }
#else
#  define sq_debug(msg...)   ((void) 0)
#endif
L'idée de mettre le %p permet de vérifier que ce sont bien des sémaphores différentes, et pas des pointeurs de noms différents qui se seraient retrouvés à pointer au même endroit.

Le code qui fait le sem_post(queue1->mutex) est le suivant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int sq_close(SyncQueue *queue)
{
    int result;
 
    sem_wait(&queue->mutex);
 
    sq_debug("sq_close entered CS; size = %d", queue->size);
 
    result = !queue->closed;
    if (result)
    {
        queue->writercount = 0;
        queue->closed = true;
        sq_debug("closed by sq_close");
        sem_post(&queue->full);
    }
 
    sleep(10);
    sq_debug("sleep(10) done");
 
    sq_debug("sq_close exiting CS; size = %d", queue->size);
 
    sem_post(&queue->mutex);
 
    return result ? EXIT_SUCCESS : EXIT_FAILURE;
}
Le sleep(10) sert à donner le temps à tous mes autres threads de se retrouver dans une situation bloquante, afin que leurs messages de debug ne me gênent pas.

Et le code qui fait le sem_wait(queue3->full) est le suivant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int sq_dequeue(SyncQueue *queue, void **item)
{
    SyncQueueNode *node;
 
    sem_wait(&queue->full);
    sem_wait(&queue->mutex);
 
    sq_debug("sq_dequeue entered CS; size = %d; closed = %d", queue->size,
        queue->closed);
 
    /* Closed queue */
    if (queue->closed && (!queue->first))
    {
        sq_debug("can't dequeue, the queue is closed and empty");
 
        sem_post(&queue->mutex);
        sem_post(&queue->full);
 
        return EXIT_FAILURE;
    }
 
    assert(queue->size > 0);
 
    ...
}
Lorsque je lance mon programme, puis appelle sq_close(queue1), les derniers messages de debug que je reçois sont :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
sq 1: sleep(10) done
sq 1: sq_close exiting CS; size = 9
sq 1: post to &queue->mutex (0xbfb6ff9c) at line 359
sq 3: wait done for &queue->full (0xbfb70074) at line 235
sq 3: wait for &queue->mutex (0xbfb70094) at line 236
sq 3: wait done for &queue->mutex (0xbfb70094) at line 236
sq 3: sq_dequeue entered CS; size = 0; closed = 0
tracesweb: syncqueue.c:252: sq_dequeue: Assertion `queue->size > 0' failed.
Abandon
Notant que la queue3 bloque sur son queue->full depuis le début du programme.

Je ne parviens vraiment pas à m'expliquer commant le sem_post(queue1->mutex) libère le sem_wait(queue3->full)

Est-ce que quelqu'un aurait une idée d'explication ? Parce que, là, ça me fout en l'air tout mon programme

Edit : avant que vous ne posiez la question : je développe sous Linux et Solaris (même problème des deux côtés). Et oui, j'ai bien fait sem_init sur toutes mes sémaphores avant de les utiliser.

d'avance