Bootstrap

Linux下线程的创建、终止、分离与等待

目录

前言

一、认识线程

二、线程控制

1.创建

2.终止

3.等待与分离

总结


前言

提示:这里可以添加本文要记录的大概内容:

        我们知道并发是轮询进行的,而线程就是实现并发处理的。下面的代码都是同一个代码,除去第一次出现的代码是完整的,下面出现一部分是说明这一部分改了一下,没有出现的说明该代码没有被修改。下面有的线程写成进程了,担待担待


提示:以下是本篇文章正文内容,下面案例可供参考

一、认识线程

线程的概念:

        线程是操作系统中能够进行运算调度的最小单位,是进程中的一条执行流。通俗来讲,

        进程的工厂,线程是工人,工人有很多岗位可以做不同的事情,这些工人组合一起工厂

        才能运行。

在Linux系统中,执行流是通过pcb实现的,进程中的线程共享了进程中的大部分资源,相较于传统的pcb较为轻量化,也被称之为轻量化进程。

     

线程间的独有和共享

        独有:每个线程所独有的数据-每个线程自己的独立副本,互不干扰。

                        如:标识符、栈、上下文数据、信号屏蔽字、优先级等

        共享:进程中的pcb共享资源-多个线程可以访问的资源

                        如:虚拟地址空间、IO信息、信号处理方式、工作路径等

注意点:一个进程至少要有一个线程能够进行任务处理。 能用于进程间的通信方式也能用于线程

二、控制线程

        对线程的操作有三点:创建、终止、等待与分离。由于系统并没有直接用于进行线程控制的系统调用接口,所以用于实现线程控制的大多都是对系统调用接口进行封装而来的。 

1.创建

接口:

        1、 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *

               (*start_routine) (void *), void *arg);        //用于创建一个新的线程

参数:

        pthread_t *thread:是一个指向pthread_t类型变量的指针,用于存储被创建出的线程ID

        const pthread_attr_t *attr:用于指定线程的属性,通常置NULL

        void *(*start_routine) (void *):传入一个函数地址,这个地址是线程要运行的函数。这

                                                         个函数必须返回void*并且接收的参数是void*类型的参数

        void *arg:给系统函数设置的参数,可以传递任何类型的数据

返回值:成功返回0,失败返回错误码

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void* prin(void* arg){
    while(1){
        printf("创建进程成功,并且传入的数据是:%s\n", (char*)arg);
        sleep(1);
        }
        return NULL;
}

int main(){
        pthread_t thread;       //创建一个用于存储进程ID的变量
        char* data = "2024-10-25";
        //创建一个进程
        if(pthread_create(&thread, NULL, prin, (void*)data) != 0){
                printf("创建线程失败");
                return -1;
        }
    while(1){
        printf("cpu正常调度的函数\n");
        sleep(1);
    }
        return 0;
}

2.终止

终止就是:如何退出线程

        我们首先知道,一个程序的最小调度单位是函数,而一个进程的最小执行流是线程。在上面我们创建线程要运行的函数void*prin(),这是线程的入口函数。

        1、每个线程都有一个如何函数,当这个函数运行到return的时候就退出运行的。

        2、当进程退出的时候,里面的所有线程也全部退出。

        3、main函数中的ruturn退出的是进程。

        4、void pthread_exit(void* retval)退出线程的函数,放入我们的自定义线程中就会自动退出。但若放入主线程中,主线程会退出而子线程不会退出,也就是进入了僵尸状态。重点普通线程退出之后,为了能够保存返回值,用户态的空间并没有被回收释放,而是需要被其他线程等待获取返回值之后才会释放。和进程的等待类似。

        5、int pthread_cancel(pthread_t tid);    这个函数是取消指定线程的运行,并且会退出返回值。

void* prin(void* arg){
    while(1){
        printf("创建进程成功,并且传入的数据是:%s\n", (char*)arg);
        sleep(5);
        pthread_exit(NULL);    退出线程
        }
        return NULL;
}

int main(){
        pthread_t thread;       //创建一个用于存储进程ID的变量
        char* data = "2024-10-25";
        //创建一个进程
        if(pthread_create(&thread, NULL, prin, (void*)data) != 0){
                printf("创建线程失败");
                return -1;
        }
    while(1){
        printf("cpu正常调度的函数\n");
        sleep(1);
        pthread_cancel(thread);
    }
        return 0;
}

3.等待与分离

线程等待:等待一个线程退出,获取它的返回值,释放它的全部资源。一个线程被创建出来

                  之后,默认有一个分离属性,值为joinable,处于joinable状态的线程退出的时

                  候,不会自动释放资源,需要获取返回值在释放资源。当一个我们需要等待线程

                  退出,和想要获取返回值的时候,用线程等待。

        接口:int pthread_join(pthread_t thread, void **retval);  阻塞接口,等待线程没有退出

                                                                                                 会一直等待。

                        **retval:指向指针的指针,用于保存返回值,返回值未一级指针,如果不想

                                       要返回值可以置NULL;

线程分离:将默认是分离属性设置为detach,分离属性处于detach状态的线程,退出后会自

                  动释放所有资源。此时的线程是不需要被等待的,等待也不一定能获取返回值。

                  当我们不需要等待线程的退出,并且不需要返回值,就可以用线程分离

        接口:int pthread_detach(pthread_t thread);        仅仅用于设置分离属性

void* prin(void* arg){
    int sum = 3;
    while(1){
        printf("创建进程成功,并且传入的数据是:%s\n", (char*)arg);
        sleep(1);
        sum--;
            if(sum == 0){
                pthread_exit(NULL);
            }
        }
        return NULL;
}

int main(){
        pthread_t thread;       //创建一个用于存储进程ID的变量
        char* data = "2024-10-25";
        //创建一个进程
        if(pthread_create(&thread, NULL, prin, (void*)data) != 0){
                printf("创建线程失败");
                return -1;
        }
        pthread_join(thread, NULL);
        printf("等待完毕退出线程\n");
    while(1){
        printf("cpu正常调度的函数\n");
        sleep(1);
        pthread_cancel(thread);
    }
        return 0;
}
线程等待

int main(){
        pthread_t thread;       //创建一个用于存储进程ID的变量
        char* data = "2024-10-25";
        //创建一个进程
        if(pthread_create(&thread, NULL, prin, (void*)data) != 0){
                printf("创建线程失败");
                return -1;
        }
//      pthread_join(thread, NULL);
        pthread_detach(thread);
    while(1){
        printf("cpu正常调度的函数\n");
        sleep(1);
        pthread_cancel(thread);
    }
        return 0;
}

 cup同时调度两个线程,当遇见分离属性接口的时候直接改变分离属性,退出线程

;