多线程多进程
操作系统中 多线程/多进程。
多进程/多线程 状态以及状态转换: 新建,就绪,运行,阻塞,死亡/终止。
进程的五个状态,其实也可以用在线程上。
就绪和阻塞都是进程线程停止工作,暂停状态,不再运行。
就绪表明进程线程有使用cpu的资格,需要等待调度。也叫可运行状态。可运行状态 表明线程可执行的所有条件都满足了(比如锁等),只要等cpu调度运行就可以。
阻塞表明完全没有使用cpu的资格。
一般说的线程 睡眠,休眠,挂起,等待 等等 都是指进程/线程 从运行状态进入非运行状态,可能是就绪或阻塞(比如时间片用完,挂起,这是指进入就绪状态的)。不过一般都是进入阻塞状态的。 (并没有进入死亡状态的)。
线程终止,是指进入终止/死亡状态。
一般进程线程sleep是进入就阻塞状态。时间到,转为就绪,等待调度。 yield是直接进入就绪状态。
平时编程时,其实说的线程阻塞,等待等,是笼统的说线程停止状态,不严格的区分,没有去细分就绪还是阻塞,也就是说细分的话,两种都有可能,只是将两者都笼统放在一起使用,反正线程不再工作,停止状态。具体代码中就能明显区分了。
多线程的 同步、互斥 操作。
理论:
P/V 操作 (semwait/semsignal 操作)。 操作信号量。
信号量可用于同步 互斥操作。
当信号量值为1(二元信号量) 的时候,可用做互斥。 大于1,可用做同步。
互斥是常用的操作,除了信号量,还有专门的互斥量/互斥锁/锁 用于做互斥。(锁等价于二元信号量)
其实信号量 完全可以用 锁+条件变量+额外的变量 来实现。
一般用于同步:信号量,条件变量(要配合锁)。
一般用于互斥:锁。 二元信号量。
(锁。 二元信号量。互斥操作 也能完成一些同步操作的。)
P/V 完成 同步 或 互斥。
具体实践:
Linux c:
互斥量操作
pthread_mutex_lock pthread_mutex_unlock
pthread_cond_wait pthread_cond_signal (条件变量要配合二元信号量使用)
pthread_cond_wait 阻塞当前线程,并且释放当前线程拥有的锁。
pthread_cond_signal 唤醒在该条件变量的阻塞线程。 将其放入原来锁的竞争队列中去。这时唤醒的那个线程要和其他线程对该锁进行竞争。 只有竞争成功,才能从条件变量阻塞处接着往下运行。 即条件变量唤醒的线程 是处于就绪状态,要等待os的调度的。
pthread_join
信号量操作
sem_wait sem_post
Java:
互斥:synchronized。 lock unlock。 (这些互斥 也可以完成一些同步的操作。)
同步:wait notify。 配合一些变量。 (这些同步 也会有一些互斥的效果。) (类似于C中条件变量的wait signal)
LockSupport.park, LockSupport.unpack (类似一个二元信号量,一般用于同步,因为都是自身线程pack,由其他线程unpack,所以一般是用做同步)
其他:
join。yield。
多线程 同步 互斥过程中可能出现的问题。
死锁,饥饿,
代码Demo。
加锁 进入阻塞状态。
获得锁,进入就绪状态,等待调度。调度得到cpu资格,进入运行状态。
yield 直接进入就绪状态。 等待调度。
wait 释放拥有的锁,并进入阻塞状态。 wait要配合锁来使用的。只能在有拥有某个锁的线程中对某个锁进行wait。
notify 唤醒因条件变量阻塞的线程,进入
sleep 进入阻塞状态,时间到,进入就绪状态,等待调度。并没有释放拥有锁。
join 进入阻塞状态,等其他线程结束。
实践中,五种的状态还是比较笼统,一般还会将阻塞状态细分。
等待阻塞/Waiting,同步阻塞/Blocked,其他阻塞/Timed_Waiting。
等待阻塞: wait操作,释放拥有的锁,并进入阻塞状态。 notify后 或者 时间到后,进入 同步阻塞(要去竞争锁)。
同步阻塞在获的锁后,进入就绪状态。
其他阻塞:比如sleep(进入睡眠状态),join等。没有释放锁,进入阻塞状态。 时间到,进入就绪状态。
比如像Java中的线程状态就比较细致。
JAVA中的状态:
New、Runnable、Blocked、Waiting、Timed_Waiting和Terminated.
其中locked、Waiting、Timed_Waiting 都是阻塞状态,对应着上面的三种阻塞。
wait(1000) //释放锁吗? 如果释放锁,那么锁被其他线程占去之后,一直不还,而线程的时间又到了,怎么办?
会释放锁。 时间到或者notify 之后 进入同步阻塞状态,去争夺锁。
https://www.jianshu.com/p/e2b22c6bcd22
interrupt 中断。并不是完全让线程结束变为terminated,是否变为terminated由程序员决定。程序员在run中判断Thread.interrupted()状态。
某个线程被调用interupt,
如果处于运行状态,只是将设置interrupt的状态,具体是停止还是怎样由 程序员写的代码决定。
如果处于阻塞状态,那么该线程会抛出InterruptedException,同时将状态转为下一个状态。
LockSupport.park() LockSupport.unpark()。 类似于二元信号量。 用做同步。 park 休眠线程/挂起线程->进入阻塞状态。 不释放拥有的锁。
Java 状态转换。
Java 多线程相关API。
参考:https://www.liaoxuefeng.com/wiki/1252599548343744/1304521607217185
Java 代码Demo。
1.线程的创建。
知道理论原理。
知道具体实践。具体实践和理论的互相映照。 api 以及具体使用 场景。
知道具体实践的 底层实现原理。