前言
线程指的是在一个进程中独立执行的最小单位。简单来说,线程是进程中的一个执行流,可以理解为执行程序的一条执行路径。本篇文章将对线程进行超详细讲解。
一、线程基础
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语言的其他重要的基础知识,感谢大家支持懒大王!