Linux线程的学习

线程

守护进程

守护进程的特点

后台服务进程
独立于控制终端
周期性执行某任务
不受用户登录注销影响
一般采用以d结尾的名字(服务)

进程组

进程的组长
组里边的第一进程
进程组的ID==进程中的组长的ID
进程中组长的选择
进程中的第一个进程
进程组ID的设定
进程组的ID就是组长的进程ID

会话

创建一个会话注意事项
不能是进程组长
创建会话的进程成为新进程组的组长
有些lInux版本需要root权限执行此操作
创建出的新会话会丢弃原有的控制终端
一般步骤;fork ,父亲死,儿子执行创建会话操作(setid)
获取进程所属的会话ID
pid_t getsid(pid_t pid);
创建一个会话
pid_t setid(void);

创建守护进程模型

fork子进程,父进程退出
子进程创建新会话
改变当前工作目录chdir
重设文件掩码
关闭文件描述符
执行核心工作

线程的概念

共享:
.text
.bss
.data
动态加载区
环境变量
命令行参数
-通信:全局变量,堆
不共享
一共五个线程,栈区被平均分成五块
在Linux下: 线程就是进程-轻量级进程
对于内核来货,线程就是进程
多进程和多线程的区别:
多进程: 始终共享的资源 代码、文件描述符、内存映射区--mmap
多线程:始终共享的资源:堆、全局变量,节省资源安卓线程man page ,命令:
sudo apt-get install manpages-posix-dev
查看指定线程的LWP号:
线程号和线程ID是有区别的
线程号是给内核看的
查看方式
找到程序的进程ID
ps -Lf pid
 
 
 

线程的创建

47776f38dafb4a9a895250837de6daa2.png

e9cbdbc20ebb444a912d3597c950d472.png

单个线程退出 --pthread_exit

7af64dcf9dfd476f9e862aa2b3a2d623.png

705ad8640338430cadeb9af99cf614b9.png

阻塞等待线程退出,获取线程退出状态--pthread_join

62ca42e332c24b0489e507822fbfb139.png

ae3251e428fe43d284920ba58a19ae9b.png

线程分离--pthread_detach

026a76ef72a94b7bb8940789a76fcdf5.png

9d71949390b641b8a8e2d3c66ce743a0.png

杀死(取消)线程--pthread_cancel

int pthread_cancel(pthread_t pthread);

比较两个线程ID是否相等(预留函数) --pthread_equal

int pthread_equal(pthread_t t1,pthread_t t2);

线程同步

数据混乱
 
操作了共享资源
 
CPU调度问题
 

互斥量(互斥锁)

c604fb1a130343029c29ab0acb00f2b6.png

如果没有锁的话,就会出现以下情况

3feb367399944b2fb098655d125bb63f.png

 

加锁一个执行完再执行另一个

01e575dee12c485ca4ce01f793178997.png

 

2f6ac7b118af448e941d6d2df07898f3.png

原子操作

CPU处理一个指令,进程/线程 在处理完这个指令之前是不会失去CPU的

就像原子被认为是不可分割颗粒一样

 

死锁

造成死锁的原因

1.自己锁自己

for(int i = 0;i<MAX;i++)
{
pthread_mutex_lock(&mutex);
pthread_mutex_lock(&mutex);
int crt = number;
crt++;
number = crt;
printf("thread A id = %ld,number = %d\n",pthread_self(),number);
pthread_mutex_unlock(&mutex);
usleep(10);
}
操作做完之后,一定要解锁

2.不放弃自己手中的

线程1 对共享资源A加锁成功-A锁
线程2 对共享资源B加锁成功-B锁
线程1访问共享资源B,对B锁加锁-线程1阻塞在B锁上
线程2访问共享资源A,对A锁加锁-线程2阻塞在A锁上
 

如何解决

-让线程按照一定的顺序去访问共享资源-在访问其他锁的时候,需要先将自己的锁解开
--try_lock
 

读写锁

读写锁是几把锁?
一把锁
pthread_rwlock_t lock;

读写锁的类型

读锁-对内存做读操作
写锁-对内存做写操作

读写锁的状态

读写锁的特性

线程A加读锁成功,又来了三个线程,做读操作,可以加锁成功
读共享-并行处理
线程A加写锁成功,又来了三个线程,做读操作,三个线程阻塞
写独占
线程A加读锁成功,又来了B线程加写锁阻塞,又来了C线程加读锁阻塞
读写不可以同时进行
写的优先级高

读写锁场景练习

线程A加写锁成功,线程B请求读锁
线程B阻塞
线程A持有读锁,线程B请求写锁
线程B阻塞
线程A拥有读写,线程B请求读锁
线程B加锁
线程A持有读锁,然后线程B请求写锁,然后线程C请求读锁
线程B阻塞,线程C阻塞
线程B加锁,线程C阻塞
线程C加锁
线程A持有写锁,然后线程B请求读锁,然后线程C请求写锁
线程B阻塞,线程C阻塞
线程C加锁, 线程B阻塞
线程B加锁

读写锁的适用场景

互斥锁-读写串行
读写锁:
读:并行
写:串行
程序中的读操作 > 写操作的时候
代码实现
feb88d3df99a4a9498f3004061480a9a.png
结果显示
 
4f219ece81164cc8af5c66272def3a7b.png

 

 

 

条件变量

条件变量
阻塞线程
不是什么时候都能阻塞线程链表头节点
Node*head = NULL;
while(head == NULL)
{
//我们想让代码在这个位置阻塞
//等待链表中有了节点之后再继续向下运行
//使用到了后面要讲的条件变量‐阻塞线程
}
//链表不为空的处理代码
xxxx

1.条件变量是锁吗?

不是锁,但是条件变量能够阻塞线程
使用条件变量+互斥量
互斥量:保护一块共享数据
条件变量:引起阻塞
生产者和消费者模型

2.条件变量的两个动作

条件不满足,阻塞线程
当条件满足,通知阻塞的线程开始工作

3.条件变量的类型

pthread_cond_t cond ;
conditon 条件

4.主要函数:

初始化一个条件变量
pthread_cond_init(pthread_cond_t * restrict cond,
const pthread_condattr_t * restrict attr
);
销毁一个条件变量
pthread_cond_destroy(pthread_cond_t * cond);
阻塞等待一个条件变量
pthread_cond_wait(
pthread_cond_t *restrict cond,
pthread_mutex_t * restrict mutex
);
阻塞线程
将已经上锁的mutex解锁
该函数解除阻塞,对互斥锁加锁限时等待一个条件变量
pthread_cond_timedwait(
pthread_cond_t * restrict cond,
pthread_mutex_t * restrict mutex,
const struct timespec * restrict abstime
);
唤醒至少一个阻塞在条件变量上的线程
pthread_cond_signal(pthread_cond_t* cond);
唤醒全部阻塞在条件变量上的线程
pthread_cond_broadcast(pthread_cond_t * cond);

练习

使用条件变量实现生产者,消费者模型
2f49ae8c55604915ac009f79dae15960.png
0b2c92b3fb4b4c83b4ffc2408ecc67dc.png
 
d1c58edeb59e44e492f2528b6b488a70.png
 

 

信号量

1.头文件-semaphore.h

2.信号量类型

sem_t sem;
加强版的互斥锁

3.主要函数

初始化信号量
sem_init(sem_t *sem,int pshared,unsigned int value);
0-线程同步1-进程同步
value-最多有几个线程操作共享数据
销毁信号量
sem_destroy(sem_t *sem);
加锁
sem_wait(sem_t *sem);
调用一次相当于对sem做了一次 -- 操作
如果sem值为0,线程会阻塞
尝试加锁
sem_trywait(sem_t *sem);
sem == 0;加锁失败,不阻塞,直接发牛
限时尝试加锁
sem_timewait(sem_t *sem,xxxx);
解锁++
sem_post(sem_t *sem);
对sem做了++ 操作

4.练习

使用信号量实现生产者,消费者模型
ffc62d713dfe46d8814b02b34a529566.png
 
012bbbd1dc754a97a1c30362d7803845.png

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值