【1】线程
(1)线程的定义:
每个用户进程有自己的独立的地址空间,task_struct 和地址空间映射表
一起用来表示一个进程。为了提高系统的性能,许多操作系统规范里引入了轻量级进程的概念,
也被称为线程。
(2)线程的特点:
1、一个进程中的所有线程可以访问该进程的组成部件,如内存、全局变量------线程在进程的内部
2、线程拥有自己独立的的堆栈和局部变量。(线程ID)
3、线程的创建速度快、系统资源开销小。
4、因此线程有时被称为轻量级进程(Lightweight Process,LWP
(3)线程与进程的关系
逻辑:
--- 一个进程至少有一个线程,称为主线程.----子线程由主线程创建出来的
--- 其他所有线程都是依附于主线程(进程)存在的------》主线程在,子线程在,主线程无,子线程无。
结论:进程之间空间独立,互不影响
线程共享进程空间,主线程影响各线程。
空间:
--- 进程间内存相对独立,一个进程崩溃后,一般不会影响其它进程。
--- 线程没有自己的地址空间,主线程死掉其它线程立即结束;
效率:
--- 进程在切换时,耗费资源较大,效率较低
--- 线程属于轻量级进程,效率比较高。
(4)线程的创建
pthread_create
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
函数的功能:创建(开启)一个新的子线程(在主线程的基础上)
参数:thread 线程id
attr 默认分配线程的堆栈空间以及属性信息,一般传NULL
start_ruotine 线程的执行体
void *(*start_routine) (void *)
典型的函数指针:也是一个回调函数(***)
注意:*start_routine 传一个地址 一般函数名可以作为地址传入
arg 为第3个参数传参
返回值:成功返回0,失败-1
pthread_self
pthread_t pthread_self(void);
函数的功能:获取当前线程的id
参数:无
返回值:线程id
pthread_exit
void pthread_exit(void *retval);
函数的功能:结束一个线程,并保存线程的状态
参数:retval 用于保存线程结束时的状态信息
返回值:无
pthread_join
int pthread_join(pthread_t thread, void **retval);
函数的功能:回收子线程的资源
参数:thread 指定子线程id
retval 保存线程结束时状态
返回值:成功返回0,失败-1
(5)线程间的通信方式-全局变量
结论:因为多个线程共享进程空间,所以我们通过全局变量变量通信。
当主线程启动起来,在当前进程内部多个线程抢占cpu
【2】线程间的同步互斥机制---
(1)同步:多个线程按照约定顺序共同的完成一个任务。
(2)互斥:保证共享资源(临界资源)(全局变量)操作的完整性,为了实现原子操作。
(3)同步与互斥的关系
同步的基础使互斥,实现同步,一定会实现互斥。
实现互斥不一定实现同步。
(4)线程间的同步互斥机制有3种
1》信号量(无名信号量)
线程的同步机制---信号量---无名信号量
信号量代表某一类资源,其值表示系统中该资源的数量
信号量是一个受保护的变量,只能通过四种操作来访问
初始化信号量
P操作(申请资源)---sem_wait
V操作(释放资源)---sem_post
销毁信号量
信号量的值为非负整数
操作步骤:
sem_init
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
函数的功能:初始化信号量
参数:sem 要初始化的信号量
pshared 0 线程间
>0 进程间
value 信号量的初始值(资源的数量)
返回值 :成功返回0,失败-1;
sem_post
int sem_post(sem_t *sem);
函数的功能:释放信号量(资源)
参数:sem 信号量
返回值:成功返回0,失败-1;
sem_wait
int sem_wait(sem_t *sem);
函数的功能:申请资源/信号量(消耗资源)
参数:sem 要消耗的资源/信号量
返回值:成功返回0,失败-1;
sem_destroy
int sem_destroy(sem_t *sem);
函数的功能:销毁信号量
参数:sem 要销毁的信号量
返回值:成功返回0,失败-1
2》条件变量(有名信号量)----线程间同步
注意:使用条件变量的时候必须结合互斥锁才能实现同步。
操作步骤:
pthread_cond_init
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
函数的功能:初始化条件变量
参数:cond 要初始化的条件变量
attr 条件变量属性信息 NULL
返回值:成功返回0,失败-1
pthread_cond_wait
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
函数的功能:等待条件的发生
参数:cond 等待发生的条件
mutex 互斥锁
返回值:成功返回0,失败-1
pthread_cond_signal
int pthread_cond_signal(pthread_cond_t *cond);
函数的功能:发送线程结束条件
参数:cond 条件信息
返回值:成功返回0,失败-1;
pthread_cond_destroy
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
函数的功能:销毁条件变量
参数:cond 要销毁的条件变量
返回值:成功返回0,失败-1
注意:
条件变量有一个致命的缺点,就是需要先处于等待信号发生的状态,因为信号的发生时刻是内核操作的
程序员无法预知,如果先发送信号,再处于等待状态,就会将信号漏掉,此时就会一直阻塞等待
解决办法:
调用延时函数sleep();
3》互斥锁
互斥锁重要用来保护临界资源
每个临界资源都由一个互斥锁来保护,任何时刻最多只能有一个线程访问该资源。
线程必须先获取互斥锁才能访问临界资源,访问完资源后释放该资源,如果无法获得锁,线程会阻塞直到获得
锁为止。
操作步骤:
pthread_mutex_init
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
函数的功能:初始化互斥锁
参数:mutex 要初始化的锁
attr 锁的属性信息,一般为NULL 默认设置
返回值:成功返回0,失败-1;
pthread_mutex_lock
int pthread_mutex_lock(pthread_mutex_t *mutex);
函数的功能:上锁
参数:mutex 要上得锁
返回值:成功返回0,失败-1
pthread_mutex_unlock
int pthread_mutex_unlock(pthread_mutex_t *mutex);
函数的功能:解锁
参数:mutex 要解锁的那把锁
返回值:成功返回0,失败-1
pthread_mutex_destroy
函数的功能:销毁互斥锁
参数:mutex 要销毁的锁
返回值:成功返回0,失败-1;
例子:定义3个全局变量count,value1,value2,在主线程当中循环对count++,count操作完事后
分别将count的值赋值给value1,value2,子线程当中,判断如果value1!=value2时,打印count,value1,value2
注意:
1)锁的是对的出现的,有上锁必有解锁的过程
2)互斥锁使用必须所有的线程都遵循这个规则,如果只有部分线程遵循这个规则,互斥锁失效
3)当一个线程申请到这个锁的时候,其他线程阻塞等待,直到把锁释放,其他的线程才有申请锁的机会
否则一直等待。
4)抢占锁的顺序不一定。谁都有可能先抢占到。
linux线程学习笔记
猜你喜欢
转载自blog.csdn.net/xiaohu1996/article/details/81288296
今日推荐
周排行