Maison  >  Article  >  Opération et maintenance  >  Analyse de code d'exemple de programmation multithread Linux

Analyse de code d'exemple de programmation multithread Linux

王林
王林avant
2023-05-26 22:04:041547parcourir

Prenons d'abord un exemple. Nous créons deux threads pour incrémenter un nombre. Peut-être que cet exemple n’a aucune valeur pratique, mais avec un léger changement, nous pouvons l’utiliser ailleurs.

Code :

/*thread_example.c : c multiple thread programming in linux
 *author : falcon
 *e-mail : tunzhj03@st.lzu.edu.cn
 */
#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#define max 10

pthread_t thread[2];
pthread_mutex_t mut;
int number=0, i;

void *thread1()
{
    printf ("thread1 : i&#39;m thread 1/n");

    for (i = 0; i < max; i++)
    {
        printf("thread1 : number = %d/n",number);
        pthread_mutex_lock(&mut);
            number++;
        pthread_mutex_unlock(&mut);
        sleep(2);
    }


    printf("thread1 :主函数在等我完成任务吗?/n");
    pthread_exit(null);
}

void *thread2()
{
    printf("thread2 : i&#39;m thread 2/n");

    for (i = 0; i < max; i++)
    {
        printf("thread2 : number = %d/n",number);
        pthread_mutex_lock(&mut);
            number++;
        pthread_mutex_unlock(&mut);
        sleep(3);
    }


    printf("thread2 :主函数在等我完成任务吗?/n");
    pthread_exit(null);
}

void thread_create(void)
{
    int temp;
    memset(&thread, 0, sizeof(thread));     //comment1
    /*创建线程*/
    if((temp = pthread_create(&thread[0], null, thread1, null)) != 0) //comment2   
        printf("线程1创建失败!/n");
    else
        printf("线程1被创建/n");

    if((temp = pthread_create(&thread[1], null, thread2, null)) != 0) //comment3
        printf("线程2创建失败");
    else
        printf("线程2被创建/n");
}

void thread_wait(void)
{
    /*等待线程结束*/
    if(thread[0] !=0)      {       //comment4          pthread_join(thread[0],null);
        printf("线程1已经结束/n");
     }
    if(thread[1] !=0)      {         //comment5        pthread_join(thread[1],null);
        printf("线程2已经结束/n");
     }
}

int main()
{
    /*用默认属性初始化互斥锁*/
    pthread_mutex_init(&mut,null);

    printf("我是主函数哦,我正在创建线程,呵呵/n");
    thread_create();
    printf("我是主函数哦,我正在等待线程完成任务阿,呵呵/n");
    thread_wait();

    return 0;
}

Compilons-le et exécutons-le d'abord

Citation :

falcon@falcon:~/program/c/code/ftp$ gcc -lpthread -o thread_example thread_example.c
falcon@falcon:~/program/c/code/ftp$ ./thread_example
我是主函数哦,我正在创建线程,呵呵
线程1被创建
线程2被创建
我是主函数哦,我正在等待线程完成任务阿,呵呵
thread1 : i&#39;m thread 1
thread1 : number = 0
thread2 : i&#39;m thread 2
thread2 : number = 1
thread1 : number = 2
thread2 : number = 3
thread1 : number = 4
thread2 : number = 5
thread1 : number = 6
thread1 : number = 7
thread2 : number = 8
thread1 : number = 9
thread2 : number = 10
thread1 :主函数在等我完成任务吗?
线程1已经结束
thread2 :主函数在等我完成任务吗?
线程2已经结束

Dans l'exemple de code Les commentaires devrait être plus clair. Je vais maintenant citer plusieurs fonctions et variables mentionnées ci-dessus sur Internet.

Citation :

Opérations liées aux threads

一pthread_t

pthread_t est dans le fichier d'en-tête /usr/include/ bits/ Défini dans pthreadtypes.h :
Typedef unsigned long int pthread_t
C'est l'identifiant d'un thread.

二pthread_create

La fonction pthread_create permet de créer un thread. Son prototype est :
extern int pthread_create __p ((pthread_t *__thread, __const pthread_attr_t *__attr ,
void *(*__start_routine) (void *), void *__arg));
Le premier paramètre est un pointeur vers l'identifiant du thread, le deuxième paramètre est utilisé pour définir les attributs du thread et le troisième paramètre Le paramètre est l'adresse de départ du thread exécutant la fonction, et le dernier paramètre est le paramètre de la fonction en cours d'exécution. Ici, notre thread de fonction ne nécessite pas de paramètres, donc le dernier paramètre est défini sur un pointeur nul. Nous définissons également le deuxième paramètre sur un pointeur nul, qui générera un thread avec les attributs par défaut. Nous expliquerons le paramétrage et la modification des attributs du thread dans la section suivante. Lorsque le thread est créé avec succès, la fonction renvoie 0. Si ce n'est pas 0, la création du thread échoue. Les codes de retour d'erreur courants sont eagain et einval. Le premier signifie que le système restreint la création de nouveaux threads, par exemple, le nombre de threads est trop élevé ; le second signifie que la valeur de l'attribut du thread représentée par le deuxième paramètre est illégale. Une fois le thread créé avec succès, le thread nouvellement créé exécute la fonction déterminée par le paramètre trois et le paramètre quatre, et le thread d'origine continue d'exécuter la ligne de code suivante.

三 pthread_join pthread_exit
 
La fonction pthread_join permet d'attendre la fin d'un fil. Le prototype de la fonction est :
extern int pthread_join __p ((pthread_t __th, void **__thread_return));
Le premier paramètre est l'identifiant du thread à attendre, et le deuxième paramètre est un identifiant défini par l'utilisateur. pointeur , qui peut être utilisé pour stocker la valeur de retour du thread en attente. Cette fonction est une fonction bloquant les threads. La fonction qui l'appelle attendra la fin du thread en attente. Au retour de la fonction, les ressources du thread en attente sont récupérées. Il existe deux manières de terminer un thread. L'une est comme dans notre exemple ci-dessus. Lorsque la fonction se termine, le thread qui l'a appelée se termine également via la fonction pthread_exit. Son prototype de fonction est :
extern void pthread_exit __p ((void *__retval)) __attribute__ ((__noreturn__));
Le seul paramètre est le code retour de la fonction, tant que le deuxième paramètre thread_return in pthread_join Non nul, cette valeur sera transmise à thread_return. La dernière chose à noter est qu'un thread ne peut pas être attendu par plusieurs threads, sinon le premier thread à recevoir le signal revient avec succès et les threads restants qui appellent pthread_join renvoient le code d'erreur esrch.
Dans cette section, nous avons écrit le fil de discussion le plus simple et maîtrisé les trois fonctions les plus couramment utilisées pthread_create, pthread_join et pthread_exit. Examinons ensuite quelques propriétés courantes des threads et comment les définir.

Mutex lock Related

Le verrouillage Mutex est utilisé pour garantir qu'un seul thread exécute un morceau de code sur une période donnée.

一 pthread_mutex_init

La fonction pthread_mutex_init est utilisée pour générer un verrou mutex. Le paramètre null indique que les propriétés par défaut sont utilisées. Si vous devez déclarer un mutex pour un attribut spécifique, vous devez appeler la fonction pthread_mutexattr_init. La fonction pthread_mutexattr_setpshared et la fonction pthread_mutexattr_settype sont utilisées pour définir les attributs de verrouillage mutex. La fonction précédente définit l'attribut pshared, qui a deux valeurs, pthread_process_private et pthread_process_shared. Le premier est utilisé pour synchroniser les threads dans différents processus, et le second est utilisé pour synchroniser différents threads dans ce processus. Dans l'exemple ci-dessus, nous utilisons l'attribut par défaut pthread_process_private. Ce dernier est utilisé pour définir le type de verrouillage mutex. Les types facultatifs sont pthread_mutex_normal, pthread_mutex_errorcheck, pthread_mutex_recursive et pthread _mutex_default. Ils définissent respectivement différents mécanismes de listing et de déverrouillage. Dans des circonstances normales, le dernier attribut par défaut est sélectionné.

二pthread_mutex_lock pthread_mutex_unlock pthread_delay_np

L'instruction pthread_mutex_lock commence à se verrouiller avec un mutex, et le code suivant est verrouillé jusqu'à ce que pthread_mutex_unlock soit appelé, c'est-à-dire qu'il ne peut être verrouillé que par un en même temps Exécution de l'appel de thread. Lorsqu'un thread s'exécute sur pthread_mutex_lock, si le verrou est utilisé par un autre thread à ce moment-là, le thread est bloqué, c'est-à-dire que le programme attendra qu'un autre thread libère le verrou mutex.

Attention :

1 Il convient de noter que les deux mises en veille ci-dessus ne sont pas seulement à des fins de démonstration, mais également pour laisser le thread dormir pendant un certain temps, laisser le thread libérer le verrou mutex et attendre qu'un autre thread l'utilise verrouillage. Ce problème est expliqué dans la référence 1 ci-dessous. Cependant, il ne semble pas y avoir de fonction pthread_delay_np sous Linux (je l'ai essayée et il m'a été demandé qu'il n'y avait aucune référence à la fonction définie), j'ai donc utilisé sleep à la place. Cependant, une autre méthode est donnée dans la référence 2, qui semble le faire. être remplacé par pthread_cond_timedwait , ce qui donne un moyen d'y parvenir.

2 Veuillez faire attention aux commentaires 1 à 5 à l'intérieur, c'est là que le problème m'a pris plusieurs heures à découvrir.
S'il n'y a pas de commentaire1, comment4 et comment5, cela provoquera une erreur de segmentation lors de pthread_join. De plus, les commentaires2 et comment3 ci-dessus en sont la cause première, alors n'oubliez pas d'écrire l'intégralité du code. Étant donné que le thread ci-dessus peut ne pas être créé avec succès, il est impossible d'attendre la fin de ce thread et une erreur de segmentation se produit (une zone mémoire inconnue est accédée) lors de l'utilisation de pthread_join. De plus, lorsque vous utilisez memset, vous devez inclure le fichier d'en-tête string.h

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer