day30——零基础学嵌入式之线程2.0
一、进程和线程的对比
线程 | 进程 | |
定义 | 轻量级的进程。是进程中的执行单元,作为CPU调度的基本单位 | 进程时程序的一次执行过程,作为CPU的资源分配的基本单位 |
优势 |
| 创建多个子进程,进程之间空间相互独立---进程的稳定性、可靠性、安全性高 |
缺点 |
| 进程间,共享数据不方便 |
二、解决线程资源竞争问题 --- 线程互斥
1.名词解释
- 临界资源----共享资源
- 临界区----:一段代码区域(访问临界资源的那段代码)
- 原子操作----要么不操作,如果要操作,一定是一次性完成的操作,不可被打断;
- 互斥----在多线程中对临界资源的排他性访问
- 互斥机制===》互斥锁===》保证临界资源团的访问控制;
为了保证临界资源(共享资源)的完整操作,增加了锁的机制,即同时满足互斥访问(线程1访问,线程2不可被访问),+原子性操作(访问的整个过程必须完整,不可被打断)。
2.框架:
定义互斥锁 ===》 齿梳化锁 ===》 加锁 ===》 解锁 ===》 销毁
⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐
3.函数
pthread_mutex_t +锁命名 【在全局变量中定义】
pthread_mutex_t +锁命名 +PTHREAD_MUTEX_INITIALIZER 【静态初始化】
pthread_mutex_init(); 【在mian函数定义】【动态初始化】
(1)功能:将已经定义好的互斥锁初始化
(2)参数:
mutex:要初始化的互斥锁
atrr:初始化的值,一般默认 NULL;
(3)返回值:
成功返回0;
失败返回非0;
pthread_mutex_lock(); 【加锁】
(1)用指定的互斥锁开始加锁代码,加锁后的代码到解锁部分代码属于原子操作;在加锁期间其他进程/线程都不可以操作该部分代码;如果函数在执行的时候,metex以及被其他部分,使用则代码阻塞;
(2)参数:mutex 用来给代码枷锁的互斥锁
(3)返回值
成功返回0;
失败返回非零;
pthread_mutex_uhlock(); 【解锁】
(1)功能:将指定的互斥锁解锁,解锁之后代码不在排他访问,一般枷锁解锁成对出现。
(2)参数:用来解锁的互斥锁;
(3)返回值:
成功返回0;
失败返回非零
pthread_mutex_d(); 【销毁锁】
(1)功能:销毁互斥锁;
(2)参数:用来销毁的互斥锁;
(3)返回值:
成功返回0;
失败返回非零;
代码示例
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
int cnt =0;
pthread_mutex_t mutex;void *cn1(void *arg)
{ for(int i =0;i<500000;++i){pthread_mutex_lock(&mutex);int tmp = cnt;tmp = tmp+1;cnt = tmp;pthread_mutex_unlock(&mutex);printf("%d\n",cnt);}pthread_exit(NULL);return NULL;
}
void *cn2(void *arg)
{for(int i =0;i<500000;++i){pthread_mutex_lock(&mutex);int tmp = cnt;tmp = tmp+1;cnt = tmp;pthread_mutex_unlock(&mutex);printf("%d\n",cnt);} pthread_exit(NULL);return NULL;
}
int main(int argc, char **argv)
{pthread_t tid1,tid2;pthread_mutex_init(&mutex, NULL);pthread_create(&tid1, NULL, cn1, NULL);pthread_create(&tid2, NULL, cn2,NULL);pthread_join(tid1, NULL);printf("-------------%d\n",cnt);pthread_mutex_destroy(&mutex);pthread_join(tid2, NULL);return 0;
}
总结:
锁的目的,保证临界资源的互斥以及原子性访问
三、线程间协作-----线程同步
- 互斥 ===》 在多线程中临界资源的排他性访问
- 同步 ===》 有一定先后顺序的,对资源的排他性访问。-------有顺序的访问
1.信号量背景:交通信号灯
(1)信号量的机制:
- 站在a的角度考虑:这块资源什么时候能用
- 站在b的角度考虑:这块资源什么时候能用
2.信号量分类
- 信号无名量 ===》 线程间通信
- 有名信号量 ===》 进程间通信
3.框架
信号量的定义 | sem_t sem; |
信号量的初始化 | sem_init() |
信号量的P操作(申请资源)、V操作(释放资源) | sem_wait()/sem_podt(); |
信号量的销毁 | sem_destroy() |
四、线程同步函数
1、semapthore 信号量的定义
sem_t sem
信号量类型 信号量的变量
2、信号量的初始化
int sem_init(sem_t *sem, int pshared, unsigned int value);
(1)功能:将已经定义好的信号量赋值。
(2)参数:
- sem:要初始化的信号量
- pthread =0 :表示线程间使用信号量;
!=0:表示进程间使用的信号量
- value:信号量的初始值,一般无名信号量-------代表一类资源的个数;
(3)返回值:
成功返回0;
失败返回-1;
3.P操作、V操作
P操作------申请资源
(if(是否有资源可用)
有;则程序往下使用资源
无;程序阻塞,等待资源可用
V操作 ------ 释放资源
if(是否有仍无需要资源)
有:释放资源给对应的任务用;
无:让资源个数加一,表示可用的资源数量多了一个,即新产生了一个资源;
int sem_wait(sem_t *sem); 【 P操作】
(1)功能:判断当前sem信号量是否有资源可用;如果sem有资源(==1),则申请资源。程序继续云顶;如果sem没有资源(==0),则线程阻塞等待,一旦有资源,组自动盛情资源并继续运行;
注意:sem申请资源后回自动执行,sem = sem -1;
(2)参数:sem要判断信号量的资源
(3)返回值:
成功返回0;
失败返回-1;
int sem_post(sem_t *sem); 【V操作】
(1)功能 : 函数可以将指定的sem信号量资源释放,并默认执行,sem = sem+1; 线程在该函数上不会阻塞。
(2)参数:sem要释放资源的信号量;
(3)返回值
成功返回0;
失败返回-1;
4.信号量的销毁
int sem_destroy(sem_t *sem);
(1)功能:使用完毕将指定的信号量销毁
(2)参数:sem要销毁的信号量
(3)返回值:
成功返回0;
失败返回-1;
信号的操作:-----主要用来实现线程间的顺序
示例代码
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>#include <semaphore.h>
sem_t sem_r;
sem_t sem_w;
char buf[1024] = {0};
void *sh1(void *arg)
{while(1){sem_wait(&sem_w);fgets(buf, sizeof(buf),stdin);sem_post(&sem_r);}
}
void *sh2(void *arg)
{while(1){sem_wait(&sem_r);printf("buf = %s",buf);sem_post(&sem_w);}
}
int main(int argc, char **argv)
{pthread_t tid1,tid2;sem_init(&sem_w, 0, 1);sem_init(&sem_r, 0, 0);pthread_create(&tid1, NULL, sh1, NULL);pthread_create(&tid2, NULL, sh2, NULL);pthread_join(tid1, NULL);pthread_join(tid1, NULL);return 0;
}
五.应用
1.什么时候用
- 锁 ----有多线程,公共资源,互斥访问
- 信号量-----多线程,公共资源,顺序访问