前端冲刺12-23 进程通信和线程通信-有效括号匹配-数组转字符串-数组展平
操作系统
进程间通信(IPC)
-1.管道(无名管道,命名管道)
-2.消息队列
-3.Socket
-4.Stream
-5.信号量
-6.共享存储
–管道(无名管道)
管道,通常指无名管道,是unix系统IPC最古老的形式
特点:
1.它是半双工的(即一个数据只能在一个方向上流动),具有固定的读端和写端
2.它只能用于具有亲缘关系的进程之间的通信
3.它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read,write等函数。但是它不是普通的文件,并不属于任何文件系统
–管道(FIFO)也称命名管道,它是一种文件类型。
特点:
1.FIFO可以在无关的进程之间交换数据,与无名管道不同
2.FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中
FIFO的通信方式类似于在进程中使用文件来传输数据,FIFO类型文件同时具有管道的特性,在数据读出时,FIFO管道中同时清除数据
–消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列有一个标识符进行标识
特点:
1.消息队列是面向记录的,其中的消息具有特定格式以及特定的优先级
2.消息队列独立于发送与接收进程,进程终止时,消息队列及其内容并不会删除
3.消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按照消息的类型进行读取;
–信号量
信号量是一个计数器,信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据
特点:
1.信号量用于进程间同步
2.信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作
3.每次对信号量的PV操作不仅限于对信号量增加1或减1,而且可以加减任意正整数
4.支持信号量组
–共享内存
两个或对各进程共享一个给定的存储区
特点:
1.共享内存是最快的一种IPC,因为进程是直接对内存进行存取
2.因为多个进程可以同时操作,所以需要进行同步
3.信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问
Conclusion
1.管道:速度慢,容量有限,只有父子进程能通讯
2.FIFO:任何进程之间都能通讯,但是速度慢
3.消息队列:容量受到系统限制,第一次读的时候,要考虑上一次没有读完数据的问题
4.信号量:不能传递复杂消息,只能用来互斥同步
5.共享内存区:容量可控制,速度快,但是要保持同步。
线程之间的通信
1.互斥锁
互斥锁为资源引入一个状态:锁定或者非锁定。某个线程要更改共享数据,先将其锁定其他线程不能修改。
2.信号量
一个计数器,当计数器为0时,线程请求调用资源时不会被允许,线程阻塞
3.条件变量
高级锁
-特点就是多了可以让线程挂起的方法(wait方法)和让线程唤醒的方法:(notify方法)
4.事件
线程的一个关键特性是每个线程都是独立运行且状态不可预测。
如果程序中的其他线程需要通过断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。
为了解决这些问题,我们需要使用 threading 库中的 Event 对象。Event 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。
在初始情况下,event 对象中的信号标志被设置假。
如果有线程等待一个 event 对象,而这个 event 对象的标志为假,那么这个线程将会被一直阻塞,直至该标志为真。
一个线程如果将一个 event 对象的信号标志设置为真,它将唤醒所有等待这个 event 对象的线程。
如果一个线程等待一个已经被设置为真的 event 对象,那么它将忽略这个事件,继续执行。
5.消息队列
在一个进程中,不同子线程负责不同的任务,他们之间的通信使用queue来完成。因为在一个进程中,数据变量是共享的。
queue是加了锁的安全消息队列。
算法与数据结构
有效括号
function bracket(str){
let arr1 = [];
let back = str.length-1;//len == 4
let head = 0;
for(let i = 0; i < str.length; i++){
arr1.push(str[i]);
}
while(head <= back){
if (arr1[back] === '}') {
if(arr1[head] !== '{'){
return false;
}
}else if(arr1[back] === "]"){
if(arr1[head] !== "["){
return false;
}
}else if(arr1[back] === ")"){
if(arr1[head] !== "("){
return false;
}
}else{
return false;
}
head ++;
back--;
}
return true;
}
//测试用例
console.log(bracket("{{}]"));
console.log(bracket("{{{[[]]}}}"));
console.log(bracket("{{{[][]}}}"));
console.log(bracket("[]"));
数组转换
let arr = [2,3,4];
//目标:将其转换为234字符串类型
//属性方法
let reg = new RegExp(',','g');
console.log(arr.toString().replace(reg,''));//可以将toString换成toLocalString方法
console.log(arr.join(''));//使用join方法进行数组分隔;
//自定义方法
let f1 = function (arr) {
let str = "";
for(let i = 0; i < arr.length; i++){
str = str+arr[i];
}
return str;
};
console.log(f1(arr));
let f2 = function(arr){
let sum = 10;
let res = 0;
for(let i = 0; i < arr.length; i++){
res = res*sum+arr[i];
}
return res;
};
console.log(f2(arr));
数组展平
let arr = [1,[2,[3]]];
//apply方法
function flatten(arr){
while(arr.some(item => Array.isArray(item))){
arr = [].concat.apply([],arr);
}
return arr;
}
//toString方法
let arr1 = arr.toString().split(',').map((val)=>{
return parseInt(val)
})
console.log(arr1)
//扩展运算符
function fn(arr){
let arr1 = [];
let bStop = true;
arr.forEach((val)=>{
if(Array.isArray(val)){
arr1.push(...val);
bStop = false
}else{
arr1.push(val)
}
})
if(bStop){
return arr1;
}
return fn(arr1)
}
//reduce实现
function fn(arr){
return arr.reduce((prev,cur)=>{
return prev.concat(Array.isArray(cur)?fn(cur):cur)
},[])
}
//递归实现
function fn(arr){
let arr1 = []
arr.forEach((val)=>{
if(val instanceof Array){
arr1 = arr1.concat(fn(val))
}else{
arr1.push(val)
}
})
return arr1
}