Home  >  Article  >  Operation and Maintenance  >  In-depth understanding of Linux system programming-(pthread) thread creation and use

In-depth understanding of Linux system programming-(pthread) thread creation and use

WBOY
WBOYforward
2022-02-02 07:00:312601browse

This article brings you knowledge about the creation and use of threads in Linux. I hope it will be helpful to you.

In-depth understanding of Linux system programming-(pthread) thread creation and use

1. Preface

The difference between threads and processes (1) Process: It is the smallest unit of operating system scheduling. Under Linux, you can view the detailed information of the process through commands such as ps and top. (2) Thread: It is the smallest unit of process scheduling. Each process has a main thread. The main thing doing things in the process is the thread.

(3) In the whole system, the process ID is the unique identifier, and the management of the process is realized through PID. Every time a process is created, the kernel will create a structure to store all the information about the process. Each node that stores process information also stores its own PID. When you need to manage the process, you can use this ID to achieve it (such as sending a signal). When the child process ends and needs to be recycled (the child process calls exit() to exit or the code is executed), it needs to be done through the wait() system call. The dead process that is not recycled will become a zombie process, and its process entity no longer exists, but It will occupy PID resources, so recycling is necessary.

For threads, if you want to actively terminate, you need to call pthread_exit(), and the main thread needs to call pthread_join() to recycle (provided that the thread does not set the "detachment attribute"). Sending thread signals like threads also implements inter-process communication through thread IDs: A. Shared memory B. Message queue C. Semaphore D. Named pipe E. Unnamed pipe F. Signal G. File H. Communication method between socket threads: A. Mutex B. Spin lock C. Condition variable D. Read-write lock E. Thread signal F. Global variable

The communication method used between processes requires switching the kernel Context, either to be accessed with peripherals (named pipes, files). So the speed will be slower. If the thread uses its own unique communication method, it is basically completed in its own process space, and there is no switching, so the communication speed will be faster. In other words, in addition to differences in types, the communication methods used between processes and threads also differ in speed.

Note: When a process running multi-threads catches a signal, only the main thread will be blocked, and other child threads will continue to execute without affecting it.

2. Introduction to thread-related functions

2.1 Creating threads

pthread_create is a function for creating threads in Unix operating systems (Unix, Linux, etc.). You need to specify the link library when compiling: -lpthread function prototype

#include <pthread.h>
int pthread_create
(
pthread_t *thread, 
const pthread_attr_t *attr,
void *(*start_routine) (void *), 
void *arg
);

Parameter introduction

The first parameter is a pointer to the thread identifier. The second parameter is used to set thread properties. NULL can be filled in by default. The third parameter is the starting address of the thread running function. The last parameter is the parameter to run the function. No parameters are required and NULL can be filled in. View function help under Linux: # man pthread_create

In-depth understanding of Linux system programming-(pthread) thread creation and use Return value: If the thread is created successfully, 0 is returned. If thread creation fails, an error number is returned. After the thread is successfully created, the attr parameter is used to specify various thread attributes. The newly created thread starts running from the address of the start_rtn function. This function has only one universal pointer parameter arg. If more than one parameter needs to be passed to the thread working function, then these parameters need to be put into a structure, and then the address of this structure Passed in as the parameter arg.

Example:

#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

2.2 Exit the thread

The thread terminates execution by calling the pthread_exit function, just like the process calls the exit function when it ends. The function of this function is to terminate the thread that calls it and return a pointer to an object.

The function of this function is to terminate the thread that calls it and return a pointer to an object. The return value can be obtained through the second parameter of the pthread_join function.

Function prototype

#include <pthread.h>
void pthread_exit(void *retval);

Parameter analysis The address that the thread needs to return. Note: The thread stack must be released when the thread ends, which means that the thread function must call pthread_exit() to end, otherwise it will not be released until the main process function exits

2.3 Wait for the thread to end

The pthread_join() function waits for the thread specified by thread to end in a blocking manner. When the function returns, the resources of the waiting thread are reclaimed. If the thread has ended, the function returns immediately. And the thread specified by thread must be joinable (combination attribute) attribute. Function prototype

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

Parameters The first parameter: Thread identifier, that is, thread ID, identifies the unique thread. The last parameter: a user-defined pointer used to store the address returned by the waiting thread. A return value of 0 represents success. If it fails, an error number is returned. Example of receiving thread return value:

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

2.4 Thread separation attribute

创建一个线程默认的状态是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);

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

2.5 获取当前线程的标识符

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

#include <pthread.h>
pthread_t pthread_self(void);

返回值 当前线程的标识符。 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); //释放清理函数

参数 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;
}

2.8 线程取消函数

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

头文件: #include <pthread.h>
函数原型:pthread_cancel(pthread_t tid);

相关推荐:《Linux视频教程

The above is the detailed content of In-depth understanding of Linux system programming-(pthread) thread creation and use. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.im. If there is any infringement, please contact admin@php.cn delete