2010-10-18 7 views
3

De quelles manières faut-il s'assurer qu'un groupe de pthreads démarre en même temps?Démarrage simultané des pthreads

Je ne pouvais trouver qu'un seul chemin, à savoir. initialiser un barrier dans le thread principal, puis l'attendre dans les pthreads nouvellement créés.

+1

Il existe des environnements dans lesquels cela n'est pas possible. Par exemple. ordinateurs à un seul cœur. –

+1

@Georg ou de démarrer un tas de threads N + 1 sur un ordinateur N core, de sorte qu'il n'est pas possible en général sur un ordinateur dénombrable. –

Répondre

6

C'est à peu près exactement comment je l'ai fait dans le passé.

main: 
    claim mutex 
    for each desired thread: 
     start child 
    release mutex 
    : 

child: 
    claim mutex 
    release mutex 
    : 

Notez que cela ne garantit en fait que tous les fils ont commencé avant que la première commence à faire quelque chose, juste que le thread principal qui les a créés.

Pour ce faire, vous pouvez utiliser quelque chose comme la méthode suivante:

main: 
    claim mutex 
    set unstarted to 0 
    for each desired thread: 
     start child 
     add 1 to unstarted 
    release mutex 
    : 

child: 
    claim mutex 
    subtract 1 from unstarted 
    while unstarted > 0: 
     release mutex 
     yield // if necessary 
     claim mutex 
    release mutex 
    : 

Quelle que soit l'initialisation d'un fil doit faire pour être considéré comme commencé aura lieu entre le claim et le subtract. Je vois d'après une enquête plus approfondie que les barrières sont en fait un moyen plus élégant de le faire. Ils n'étaient pas réellement disponibles dans les implémentations pthread que j'ai utilisées, ce qui explique pourquoi mon code peut sembler un peu bavard.

Cependant, je vais laisser tel quel sur le hasard que quelqu'un utilise des pthreads pré-v6 ou une méthode de threading différente (sans barrières) et parce que, comme la question l'a demandé, cette est différente de le faire.

+0

Les sémaphores POSIX ne fonctionnent pas bien avec pthreads, ou y a-t-il une autre raison de ne pas les utiliser? –

+0

@Pete, aucune idée. J'ai tendance à ne pas mélanger des choses comme ça car ils finissent toujours comme le sodium et l'eau :-) À mon avis, si vous allez utiliser des pthreads, alors utilisez-les. Ne les utilisez pas à moitié. – paxdiablo

+1

@Pete, 'sem_t' fonctionne bien avec les threads POSIX, mais ils ont plusieurs inconvénients. La première est que leur «attente» est interruptible, donc vous devez être très prudent lors de la programmation avec ceci. Ensuite, démarrer des threads simultanément n'est pas si facile avec eux: si vous n'utilisez qu'un sémaphore, le thread maître doit faire N opérations individuelles pour lancer les autres. Ce n'est pas ce que j'appellerais exactement "lancé simultanément". –

0

Vous pouvez utiliser pthread_cond_broadcast. Ils ne seront pas lancés complètement simultanément à cause du mutex. Vous pouvez essayer d'utiliser un mutex différent pour chaque thread, mais l'utilisation de mutex différents pour la même variable de condition est indéfinie.

#include <pthread.h> 

pthread_mutex_t join_mut = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

void thread_function (void *param) { 
    pthread_mutex_lock(&join_mut); 
    pthread_cond_wait(&cond, &join_mut); 
    pthread_mutex_unlock(&join_mut); 

    /* Thread work here */ 
} 

enum { threads = 16 }; 

int main() { 
    int i; 
    pthread_t thread_table[threads]; 

    for(i = 0; i < threads; i++) { 
    pthread_create(&(thread_table[i]), NULL, thread_function, NULL); 
    } 

    /* Wait for all threads to be queued */ 

    pthread_cond_broadcast(&cond); 
} 
+1

-1 Ceci est dangereux. Le '/ * Wait * /' ne garantit en aucun cas que l'un des threads enfants sera bloqué sur la variable de condition lorsque 'broadcast' est appelé. – pilcrow

+0

@pilcrow c'est le point du commentaire, vous devez l'implémenter. Vous pouvez par exemple utiliser le mutex join_mut pour protéger un compteur de threads prêts. –

+1

Le point de la question est de définir une mise en œuvre appropriée. Autrement, vous pouvez aussi remplacer tout de main() par '/ * Implémenter quelque chose qui satisfait aux exigences * /' :) Il n'est pas clair dans votre commentaire que vous choisissiez un compteur protégé par mutex sur, par exemple, un sommeil naïf et dangereux(). – pilcrow