C/C++ 线程超详细讲解(系统性学习day10)

目录

前言

一、线程基础

1.概念

2.一个进程中多个线程特征

[2.1 线程共有资源](#2.1 线程共有资源)

[2.2 线程私有资源](#2.2 线程私有资源)

3.线程相关的api函数

[3.1 创建线程](#3.1 创建线程)

创建线程实例代码如下:

需要特别注意的是:

-lpthread和-pthread的区别

[3.2 给线程函数传参](#3.2 给线程函数传参)

传参实例代码如下:

[3.3 给线程收尸](#3.3 给线程收尸)

收尸实例代码如下:

二、线程状态转换函数说明

1.初始化条件休眠

2.条件休眠,挂起线程

3.唤醒线程

4.设置取消状态

5.设置取消方式

6.取消线程

[三 、线程状态转换图片(如图清晰可见)](#三 、线程状态转换图片(如图清晰可见))

总结


前言

线程指的是在一个进程中独立执行的最小单位。简单来说,线程是进程中的一个执行流,可以理解为执行程序的一条执行路径。本篇文章将对线程进行超详细讲解。


一、线程基础

1.概念

(1)线程:在进程空间中执行,也是一个动态的过程。

(2)一个进程对应一个程序,一个线程对应程序中的一个函数

(3)线程是该函数的一次在执行过程,该函数称为线程函数。

2.一个进程中多个线程特征

2.1 线程共有资源

(1)可执行的指令(.text)

(2)静态数据(.data/.bss/.heap)

(3)进程中打开的文件描述符

(4)信号处理函数

(5)当前工作目录

(6)用户ID

(7)用户组ID

2.2 线程私有资源

(1)线程ID (TID)

(2)PC(程序计数器)和相关寄存器

(3)堆栈

(4)局部变量

(5)返回地址

(6)错误号 (errno)

(7)信号掩码和优先级

(8)执行状态和属性

3.线程相关的api函数

3.1 创建线程

头文件:

#include <pthread.h>

Compile and link with -pthread.

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

void *(*start_routine) (void *), void *arg);

//参数1 ----- 保存线程id的变量的地址

//参数2 ----- 线程属性,一般为NULL,表示使用默认属性

//参数3 ----- 线程函数指针,必须是下面的格式:

void * xxx_fun (void * arg)

{

线程执行代码

}

//参数4 ----- 传给线程函数的参数

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

创建线程实例代码如下:
复制代码
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

void* fun(void* arg)
{
    int i;

    for(i = 0; i  < 7; i++){
        printf("我是fun\n");
        sleep(1);
    }

    return 0;
}

int main(void)
{
    int i;
    pthread_t tid;

    //fun();
    if(pthread_create(&tid,NULL,fun,NULL)){
        perror("pthread_create");
        exit(1);
    }
    for(i = 0; i  < 7; i++){
        printf("我是主函数\n");
        sleep(1);
    }
    return 0;
}
需要特别注意的是:

编译时,需要链接线程库

gcc pthread_create.c -o pthread_create -lpthread

-lpthread和-pthread的区别

两个选项都是用于链接 pthread 库的选项,但它们有一些细微的差别。

-lpthread 是告诉链接器去链接 pthread 库,这是一个标准的链接选项,可以用于链接任何库。

-pthread 是告诉编译器在编译时需要使用 pthread 库,这是一个非标准的编译选项,只能在支持它的编译器上使用。

在大多数情况下,使用 -lpthread 是更好的选择,因为它是标准的链接选项,可以在不同的编译器和操作系统上使用。而 -pthread 只能在支持它的编译器上使用。

3.2 给线程函数传参

传参实例代码如下:
复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

typedef struct{
    int sno;
    char name[20];
    float score;
}St;

void* fun(void* arg)
{
    St *p = (St*)arg;
    //printf("%d\n",*(int*)arg);
    //printf("%s\n",(char*)arg);
    printf("%d %s %.2f\n",p->sno,p->name,p->score);
    return 0;
}

int main(void)
{
    pthread_t tid;
    //int a = 120;
    //char str[] = "hello world";
    St s = {1001,"peter",98.56};

    if(pthread_create(&tid,NULL,fun,&s)){
	perror("pthread_create");
	exit(1);
    }
    
    sleep(1);
    return 0;
}

3.3 给线程收尸

int pthread_join(pthread_t thread, void **retval);

//参数1 ---- 线程的id

//参数2 ---- 保存线程返回值的指针变量的地址

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

收尸实例代码如下:
复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

typedef struct{
    int sno;
    char name[20];
    float score;
}St;

void* fun(void* arg)
{
    static int a = 112200;
    St *p = (St*)arg;
    //printf("%d\n",*(int*)arg);
    //printf("%s\n",(char*)arg);
    printf("%d %s %.2f\n",p->sno,p->name,p->score);
    return &a;
}

int main(void)
{
    pthread_t tid;
    int *p;
    //int a = 120;
    //char str[] = "hello world";
    St s = {1001,"peter",98.56};

    //创建子线程
    if(pthread_create(&tid,NULL,fun,&s)){
	perror("pthread_create");
	exit(1);
    }
    
    //给指定线程收尸,如果子线程没有结束,则主线程阻塞
    //if(pthread_join(tid,NULL)){
    if(pthread_join(tid,(void**)&p)){
	perror("pthread_join");
	exit(1);
    }
    printf("*p = %d\n",*p);

    return 0;
}

二、线程状态转换函数说明

1.初始化条件休眠

头文件:#include <pthread.h>

int pthread_cond_init (pthread_cond_t * __cond,const pthread_condattr_t * __cond_attr)

* 功能:初始化条件休眠

* 参数:

pthread_cond_t * __cond - 指向被初始化的条件变量

const pthread_condattr_t * __cond_attr- 指向条件变量的属性,使用默认值NULL

* 返回值:

失败:负数,绝对值是错误码

2.条件休眠,挂起线程

头文件:#include <pthread.h>

int pthread_cond_wait (pthread_cond_t * __cond, pthread_mutex_t *__mutex);

* 功能:条件休眠,挂起线程(调用该函数的线程被阻塞了,函数不返回,且休眠状态)

* 参数:

pthread_cond_t * __cond - 指向条件变量

pthread_mutex_t *__mutex- 指向互斥锁

* 返回值:

失败:负数,绝对值是错误码

3.唤醒线程

头文件:#include <pthread.h>

int pthread_cond_signal (pthread_cond_t *__cond);

* 功能:唤醒线程(调用该函数的唤醒被pthread_cond_wait阻塞的线程)

* 参数:

pthread_cond_t * __cond - 指向条件变量

* 返回值:

失败:负数,绝对值是错误码

4.设置取消状态

头文件:#include <pthread.h>

int pthread_setcancelstate (int __state, int *__oldstate);

* 功能:设置取消状态

* 参数:

int __state - 使能还不使能

使能取消线程,PTHREAD_CANCEL_ENABLE

int *__oldstate- 保存老状态

* 返回值:

失败 - 负数绝对值是错误码

5.设置取消方式

头文件:#include <pthread.h>

int pthread_setcanceltype (int __type, int *__oldtype);

* 功能:设置取消方式

* 参数:

int __type - 取消方式

PTHREAD_CANCEL_ASYNCHRONOUS - 异步取消

PTHREAD_CANCEL_DEFERRED - 取消延迟

int *__oldtype- 保存老方式

* 返回值:

失败 - 负数绝对值是错误码

6.取消线程

头文件:#include <pthread.h>

int pthread_cancel (pthread_t __th);

/*

* 功能:取消线程

* 参数:

pthread_t __th - 线程ID

* 返回值:

失败 - 负数绝对值是错误码

三 、线程状态转换图片(如图清晰可见)


总结

本篇文章针对C/C++ 线程进行详细讲解,希望能够帮到大家!

以后还会给大家展现更多关于嵌入式和C语言的其他重要的基础知识,感谢大家支持懒大王!

希望这篇博客能给各位朋友们带来帮助,最后懒大王请来过的朋友们留下你们宝贵的三连以及关注,感谢你们!

相关推荐
小柯博客3 小时前
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(十二)
c语言·stm32·单片机·嵌入式硬件·php·嵌入式
moxiaoran57534 小时前
uni-app学习笔记二十九--数据缓存
笔记·学习·uni-app
C++ 老炮儿的技术栈4 小时前
UDP 与 TCP 的区别是什么?
开发语言·c++·windows·算法·visual studio
wgslucky4 小时前
Dubbo报错:module java.base does not “opens java.lang“ to unnamed module
java·开发语言·dubbo
whyeekkk4 小时前
python打卡第48天
开发语言·python
pop_xiaoli5 小时前
OC—UI学习-2
学习·ui·ios
Lin Hsüeh-ch'in5 小时前
Vue 学习路线图(从零到实战)
前端·vue.js·学习
DougLiang6 小时前
关于easyexcel动态下拉选问题处理
java·开发语言
全职计算机毕业设计6 小时前
基于Java Web的校园失物招领平台设计与实现
java·开发语言·前端
恰薯条的屑海鸥6 小时前
零基础在实践中学习网络安全-皮卡丘靶场(第十五期-URL重定向模块)
学习·安全·web安全·渗透测试·网络安全学习