Maison > Opération et maintenance > exploitation et maintenance Linux > Compréhension approfondie de la programmation du système Linux - création et utilisation de threads (pthread)

Compréhension approfondie de la programmation du système Linux - création et utilisation de threads (pthread)

WBOY
Libérer: 2022-02-02 07:00:31
avant
2665 Les gens l'ont consulté

Cet article vous apporte des connaissances sur la création et l'utilisation de threads sous Linux. J'espère qu'il vous sera utile.

Compréhension approfondie de la programmation du système Linux - création et utilisation de threads (pthread)

1. Introduction

La différence entre les threads et les processus (1) Processus : c'est la plus petite unité de planification du système d'exploitation. Sous Linux, vous pouvez afficher les informations détaillées du processus via des commandes telles que ps et top. (2) Thread : il s’agit de la plus petite unité de planification de processus. Chaque processus a un thread principal. La principale chose qui fait les choses dans le processus est le fil.

(3) Dans l'ensemble du système, l'ID du processus est l'identifiant unique, et la gestion du processus est réalisée via le PID. Chaque fois qu'un processus est créé, le noyau crée une structure pour stocker toutes les informations sur le processus. Chaque nœud qui stocke les informations sur le processus stocke également son propre PID. Lorsque vous devez gérer le processus, vous pouvez utiliser cet identifiant pour y parvenir (comme envoyer un signal). Lorsque le processus enfant se termine et doit être recyclé (le processus enfant appelle exit() pour quitter ou le code est exécuté), cela doit être fait via l'appel système wait(). Le processus mort qui n'est pas recyclé deviendra un processus enfant. processus zombie, et son entité de processus n'existe plus, mais elle occupera des ressources PID, le recyclage est donc nécessaire.

Pour les threads, si vous souhaitez terminer activement, vous devez appeler pthread_exit(), et le thread principal doit appeler pthread_join() pour recycler (à condition que le thread ne définisse pas "l'attribut de détachement"). L'envoi de signaux de thread comme les threads est également réalisé via les ID de thread

Méthodes de communication entre les processus : A. Mémoire partagée B. File d'attente de messages C. Sémaphore D. Pipe nommée E. Pipe sans nom F. Signal G. Fichier H. socket entre les threads Méthode de communication : A. Mutex B. Spin lock C. Variable de condition D. Verrouillage en lecture-écriture E. Signal de thread F. Variable globale

La méthode de communication utilisée entre les processus nécessite soit de changer de contexte du noyau, soit d'accéder à des périphériques (tube nommé, fichier). La vitesse sera donc plus lente. Si le thread utilise sa propre méthode de communication unique, il est essentiellement réalisé dans son propre espace de processus et il n'y a pas de commutation, la vitesse de communication sera donc plus rapide. En d’autres termes, outre les différences de types, les méthodes de communication utilisées entre les processus et les threads diffèrent également en termes de vitesse.

Remarque : lorsqu'un processus exécutant plusieurs threads capte un signal, seul le thread principal sera bloqué et les autres threads enfants continueront à s'exécuter sans l'affecter.

2. Introduction aux fonctions liées aux threads

2.1 Création de threads

pthread_create est une fonction permettant de créer des threads dans les systèmes d'exploitation Unix (Unix, Linux, etc.). Vous devez spécifier la bibliothèque de liens lors de la compilation : -lpthread function prototype

#include <pthread.h>
int pthread_create
(
pthread_t *thread, 
const pthread_attr_t *attr,
void *(*start_routine) (void *), 
void *arg
);
Copier après la connexion

Introduction au paramètre

Le premier paramètre est un pointeur vers l'identifiant du fil. Le deuxième paramètre est utilisé pour définir les propriétés du thread. NULL peut être renseigné par défaut. Le troisième paramètre est l'adresse de départ de la fonction du thread en cours d'exécution. Le dernier paramètre est le paramètre permettant d'exécuter la fonction. Aucun paramètre n'est requis et NULL peut être renseigné. Afficher l'aide de la fonction sous Linux : # man pthread_create

Compréhension approfondie de la programmation du système Linux - création et utilisation de threads (pthread)

Valeur de retour : Si le thread est créé avec succès, 0 est renvoyé. Si la création du thread échoue, un numéro d'erreur est renvoyé. Une fois le thread créé avec succès, le paramètre attr est utilisé pour spécifier divers attributs du thread. Le thread nouvellement créé commence à s'exécuter à partir de l'adresse de la fonction start_rtn. Cette fonction n'a qu'un seul paramètre de pointeur universel arg. Si plusieurs paramètres doivent être transmis à la fonction de travail du thread, alors ces paramètres doivent être placés dans une structure. puis l'adresse de cette structure transmise en paramètre arg.

Exemple :

#include <stdio.h>
#include <pthread.h>
//线程函数1
void *pthread_func1(void *arg)
{
    while(1)
    {
        printf("线程函数1正在运行.....\n");
        sleep(2);
    }
}
//线程函数2
void *pthread_func2(void *arg)
{
    while(1)
    {
        printf("线程函数2正在运行.....\n");
        sleep(2);
    }
}
int main(int argc,char **argv)
{
    
    pthread_t thread_id1;
    pthread_t thread_id2;
   /*1. 创建线程1*/
    if(pthread_create(&thread_id1,NULL,pthread_func1,NULL))
    {
        printf("线程1创建失败!\n");
        return -1;
    }
    /*2. 创建线程2*/
    if(pthread_create(&thread_id2,NULL,pthread_func2,NULL))
    {
        printf("线程2创建失败!\n");
        return -1;
    }
    
    /*3. 等待线程结束,释放线程的资源*/
    pthread_join(thread_id1,NULL);
    pthread_join(thread_id2,NULL);
    return 0;
}
//gcc pthread_demo_code.c -lpthread
Copier après la connexion

2.2 Quitter le thread

Le thread termine l'exécution en appelant la fonction pthread_exit, tout comme le processus appelle la fonction exit à la fin. La fonction de cette fonction est de terminer le thread qui l'appelle et de renvoyer un pointeur vers un objet.

La fonction de cette fonction est de terminer le thread qui l'appelle et de renvoyer un pointeur vers un objet. La valeur de retour peut être obtenue via le deuxième paramètre de la fonction pthread_join.

Prototype de fonction

#include <pthread.h>
void pthread_exit(void *retval);
Copier après la connexion

Analyse des paramètres L'adresse de retour du fil. Remarque : la pile de threads doit être libérée à la fin du thread, ce qui signifie que la fonction du thread doit appeler pthread_exit() pour se terminer, sinon elle ne sera pas libérée tant que la fonction du processus principal ne se terminera pas

2.3 Attendez la fin du thread

Fonction pthread_join(), attendant la spécification du fil de manière bloquante Le fil se termine. Lorsque la fonction revient, les ressources du thread en attente sont récupérées. Si le thread est terminé, la fonction revient immédiatement. Et le thread spécifié par thread doit être un attribut joignable (attribut de combinaison). Prototype de fonction

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
Copier après la connexion

Paramètres Le premier paramètre : L'identifiant du fil, c'est-à-dire l'ID du fil, identifie le fil unique. Le dernier paramètre : un pointeur défini par l'utilisateur utilisé pour stocker l'adresse renvoyée par le thread en attente. Une valeur de retour de 0 représente le succès. En cas d'échec, un numéro d'erreur est renvoyé. Exemple de réception de la valeur de retour du thread :

//退出线程
pthread_exit ("线程已正常退出");
//接收线程的返回值
void *pth_join_ret1;
pthread_join( thread1, &pth_join_ret1);
Copier après la connexion

2.4 Attribut de séparation des threads

创建一个线程默认的状态是joinable(结合属性),如果一个线程结束运行但没有调用pthread_join,则它的状态类似于进程中的Zombie Process(僵死进程),即还有一部分资源没有被回收(退出状态码),所以创建线程者应该pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于进程的wait,waitpid)。但是调用pthread_join(pthread_id)函数后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。

pthread_detach函数可以将该线程的状态设置为detached(分离状态),则该线程运行结束后会自动释放所有资源。 函数原型

#include <pthread.h>
int pthread_detach(pthread_t thread);
Copier après la connexion

参数 线程标识符 返回值 0表示成功。错误返回错误码。 EINVAL线程并不是一个可接合线程。 ESRCH没有线程ID可以被发现。

2.5 获取当前线程的标识符

pthread_self函数功能是获得线程自身的ID。 函数原型

#include <pthread.h>
pthread_t pthread_self(void);
Copier après la connexion

返回值 当前线程的标识符。 pthread_t的类型为unsigned long int,所以在打印的时候要使用%lu方式,否则显示结果出问题。

2.6 自动清理线程资源

线程可以安排它退出时需要调用的函数,这样的函数称为线程清理处理程序。用于程序异常退出的时候做一些善后的资源清理。 在POSIX线程API中提供了一个pthread_cleanup_push()/pthread_cleanup_pop()函数用于自动释放资源。从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用 pthread_exit()和异常终止)都将执行pthread_cleanup_push()所指定的清理函数。

注意:pthread_cleanup_push函数与pthread_cleanup_pop函数需要成对调用。 函数原型

void pthread_cleanup_push(void (*routine)(void *),void *arg); //注册清理函数
void pthread_cleanup_pop(int execute); //释放清理函数
Copier après la connexion

参数 void (*routine)(void *) :处理程序的函数入口。 void *arg :传递给处理函数的形参。 int execute:执行的状态值。 0表示不调用清理函数。1表示调用清理函数。

导致清理函数调用的条件:

调用pthread_exit()函数

pthread_cleanup_pop的形参为1。 注意:return不会导致清理函数调用。

2.7 自动清理线程示例代码

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
//线程清理函数
void routine_func(void *arg)
{
   printf("线程资源清理成功\n");
}
//线程工作函数
void *start_routine(void *dev)
{
   pthread_cleanup_push(routine_func,NULL);
   //终止线程
   // pthread_exit(NULL);
    
   pthread_cleanup_pop(1); //1会导致清理函数被调用。0不会调用。
}
int main(int argc,char *argv[])
{
   pthread_t thread_id;  //存放线程的标识符
   /*1. 创建线程*/
   if(pthread_create(&thread_id,NULL,start_routine,NULL)!=0)
   {
      printf("线程创建失败!\n");
   } 
  /*2.设置线程的分离属性*/
   if(pthread_detach(thread_id)!=0)
   {
   printf("分离属性设置失败!\n");
   }
   while(1){}
   return 0;
}
Copier après la connexion

2.8 线程取消函数

pthread_cancel函数为线程取消函数,用来取消同一进程中的其他线程。

头文件: #include <pthread.h>
函数原型:pthread_cancel(pthread_t tid);
Copier après la connexion

相关推荐:《Linux视频教程

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!

Étiquettes associées:
source:juejin.im
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal