第3章 Linux多线程开发 3.1线程概述 3.2创建线程 3.3终止线程 3.4连接已终止的线程

3.1线程概述

线程概述

在这里插入图片描述
在这里插入图片描述

线程和进程区别

在这里插入图片描述

线程和进程虚拟地址空间

进程是读时共享,写时复制。线程共享虚拟地址空间,只是.text段(代码段)有不一样。.text会分成一个个小段,线程1、线程2…分开存储在不同的段.text。各线程执行各自的代码。栈空间也会有不同,分成一个个小段分给各线程。
在这里插入图片描述

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

在这里插入图片描述

NPTL

Linux系统线程库的发展概述
在这里插入图片描述
在这里插入图片描述

3.2 创建线程

线程操作

在这里插入图片描述

创建线程

在这里插入图片描述

出现报错及原因

在这里插入图片描述
线程是第三方库不是标准系统库,需要通过-l指定去指定库的名称
解决方案如下:
在这里插入图片描述
main函数中所有执行的代码为主线程的代码,子线程执行的代码为回调函数的代码

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

//函数指针,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);
}

显示结果:
在这里插入图片描述

3.3终止线程

在这里插入图片描述

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

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);

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

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

显示结果:
在这里插入图片描述
主线程和子线程是交替执行的,并发。
在这里插入图片描述

3.4连接已终止的线程

在这里插入图片描述
子进程一定是被父进程回收,子线程不一定需要被父线程回收,可以被任意线程回收,但一般是主线程回收子线程。如果子线程结束后不被回收,也会产生僵尸线程。
为何使用二级指针?
要想改变一级指针的值,函数调用传入参数为二级指针。

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

//全局变量,若为局部变量,栈空间数据,最后获取的是个随机的值
//线程退出时记得一定返回的是全局变量的值
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; 
}

显示结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值