【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程

文章目录

    • 3.1线程概述
      • 线程概述
      • 线程和进程区别
      • 线程和进程虚拟地址空间
      • 线程之间共享和非共享资源
      • NPTL
    • 3.2 创建线程
      • 线程操作
      • 创建线程
      • 出现报错及原因
    • 3.3终止线程
    • 3.4连接已终止的线程


3.1线程概述

线程概述

【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第1张图片并发:两队人用同一个咖啡机(本质上同一时刻只有一个进程在运行,但是切换非常快,所以看起来是好几个进程同时进行)
并行:两队人用两个咖啡机

查看指定进程的线程:ps -Lf pid(进程号)
【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第2张图片

线程和进程区别

【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第3张图片

线程和进程虚拟地址空间

进程是读时共享,写时复制。但不论怎么说,只要创建了一个新进程,内核一定先被复制。写的时候还要创建新的实际物理空间。

线程共享虚拟地址空间,只是**.text段(代码段)以及栈空间**有不一样。.text会分成一个个小段,线程1、线程2…分开存储在不同的段.text。各线程执行各自的代码。栈空间也会有不同,分成一个个小段分给各线程。
【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第4张图片

线程之间共享和非共享资源

【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第5张图片信号掩码:每个线程的信号阻塞不一样

NPTL

Linux系统线程库的发展概述
【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第6张图片查看当前线程库版本:
在这里插入图片描述

3.2 创建线程

线程操作

【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第7张图片

创建线程

【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第8张图片

出现报错及原因

在这里插入图片描述

线程是第三方库不是标准系统库,需要通过-l指定去指定库的名称
解决方案如下:加上第三方库 -pthread 或者 -lpthread

wcx@wcx-virtual-machine:~/linux/lesson29$ gcc pthread_create.c -o pthread_create -pthread

【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第9张图片

main函数中所有执行的代码为主线程的代码,子线程执行的代码为回调函数的代码

#include 
#include 
#include 
#include 

//函数指针,void*为万能指针
void * callback(void * arg) {
    printf("child thread...\n");
    printf("arg value: %d\n", *(int *)arg);
    return NULL;
}

int main() {

    pthread_t tid;

    int num = 10;

    // 创建一个子线程
    int ret = pthread_create(&tid, NULL, callback, (void *)&num);

    if(ret != 0) {
        char * errstr = strerror(ret);
        printf("error : %s\n", errstr);
    } 

    for(int i = 0; i < 5; i++) {
        printf("%d\n", i);
    }

    //预防子线程还在创建或子线程未抢占执行权,程序就退出,预防子线程的未被执行
    sleep(1);

    return 0;   // exit(0);
}

显示结果:
【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第10张图片

3.3终止线程

让主线程退出,当主线程退出时,不会影响其他正常运行的线程(子线程)。因为到这一步主线程是就退出了,就没有执行return 0,相当于exit(0),所以进程还在,就没有影响其他子进程

pthread_exit(NULL); //因为到这一步主线程是就退出了,就没有执行return 0,相当于exit(0),所以进程还在,就没有影响其他子进程

	//该句没有被执行
    printf("main thread exit\n");

	//没有执行
    return 0;   // exit(0);

【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第11张图片

#include 
#include 
#include 

void * callback(void * arg) {
    printf("child thread id : %ld\n", pthread_self());
    return NULL;    //相当于 pthread_exit(NULL);终止子线程
} 

int main() {

    // 创建一个子线程
    pthread_t tid;
    int ret = pthread_create(&tid, NULL, callback, NULL);

    if(ret != 0) {
        char * errstr = strerror(ret);
        printf("error : %s\n", errstr);
    }

    // 主线程
    for(int i = 0; i < 5; i++) {
        printf("%d\n", i);
    }

    printf("tid : %ld, main thread id : %ld\n", tid ,pthread_self());

    // 让主线程退出,当主线程退出时,不会影响其他正常运行的线程(子线程)。
    pthread_exit(NULL); //因为到这一步主线程是就退出了,就没有执行return 0,相当于exit(0),所以进程还在,就没有影响其他子进程

	//该句没有被执行
    printf("main thread exit\n");

	//没有执行
    return 0;   // exit(0);
}

【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第12张图片
下图说明主线程和子线程是交替执行的
【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第13张图片

3.4连接已终止的线程

【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第14张图片子进程一定是被父进程回收,子线程不一定需要被父线程回收,可以被任意线程回收,但一般是主线程回收子线程。如果子线程结束后不被回收,也会产生僵尸线程。

为何使用二级指针?
要想改变一级指针的值,函数调用传入参数为二级指针。
因为返回值是一个指针,想通过retval传出返回值,肯定要用指针。

int a = 0
void act(&a)(){}

肯定是这样才能改变a的值。
同理如果a是一个指针类型,形参理所当然就是二级指针

#include 
#include 
#include 
#include 

//全局变量,若为局部变量,栈空间数据,最后获取的是个随机的值
//线程退出时记得一定返回的是全局变量的值
int value = 10;

void * callback(void * arg) {
    printf("child thread id : %ld\n", pthread_self());
    // sleep(3);
    // return NULL; 
    // int value = 10; // 局部变量
    pthread_exit((void *)&value);   // return (void *)&value;
} 

int main() {

    // 创建一个子线程
    pthread_t tid;
    int ret = pthread_create(&tid, NULL, callback, NULL);

    if(ret != 0) {
        char * errstr = strerror(ret);
        printf("error : %s\n", errstr);
    }

    // 主线程
    for(int i = 0; i < 5; i++) {
        printf("%d\n", i);
    }

    printf("tid : %ld, main thread id : %ld\n", tid ,pthread_self());

    // 主线程调用pthread_join()回收子线程的资源
    int * thread_retval;//定义一个一级指针
    //传递一级指针的地址作为二级指针,并转换为void **
    ret = pthread_join(tid, (void **)&thread_retval);
    

    if(ret != 0) {
        char * errstr = strerror(ret);
        printf("error : %s\n", errstr);
    }

    printf("exit data : %d\n", *thread_retval);

    printf("回收子线程资源成功!\n");

    // 让主线程退出,当主线程退出时,不会影响其他正常运行的线程。
    pthread_exit(NULL);

    return 0; 
}

【项目 线程 1】 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程_第15张图片

你可能感兴趣的:(c++)