进程通信有哪些方式?
- 管道/匿名管道(Pipes):有亲缘关系的父子进程或兄弟进程间的通信,只存在于内存中的文件
- 有名管道(Named Pipes):严格遵循FIFO原则,存在于磁盘介质或文件系统,可以实现对本机任意两个进程的通信。
- 信号(Signal):一种比较复杂的通信方式,用于通知接收进程:某个事件已经发生。
- 消息队列(message Queuing):消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列符标识,遵循先进先出原则,存放在内核中。
只有通过内核重启,或显示删除一个消息队列时,该消息队列才会被真正删除。消息队列可以实现消息的随机查询,消息不一定以先进先出的次序读取,也可以按消息的类型读取。比FIFO更有优势。消息队列克服了信号承载量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。 - 信号量(semophores):信号量是一个计数器,用于多进程共享数据的访问,信号量的意图在于进程间同步。主要用来解决与同步相关的问题并避免竞争条件。
- 共享内存(shared memory):使得多个进程可以访问同一块内存空间,一个进程可以及时查看到对方进程对共享内存中数据的更新。这种方式需要依靠某种同步操作,比如互斥锁和信号量等。可以说是最有用的进程间通信方式。
- 套接字(Sockets): 这种方式主要用于客户端和服务器之间通过网络进行通信。套接字是支持TCP/IP的网络通信的基本操作单元,套接字中的相关函数完成通信过程。
什么是死锁?死锁的条件是什么?如何避免死锁?
-
死锁(Deadlock)描述的这样一种情况:多个进程/线程同时被阻塞,它们中的一个或全部都在等待某个资源被释放。由于进程,线程被无限期的阻塞,因此程序无法正常终止。
例子:
-
死锁的条件:
- 互斥:资源必须处于非共享模式,即一次只有一个进程可以使用。如果另一个进程申请该资源,那必须等待直到该资源被释放为止。
- 占有并等待:一个进程至少应该占有一个资源,并等待另一个资源,而该资源被其他进程所占有。
- 非抢占:资源不能被抢占。只能在持有资源的进程完成任务后,该资源所有权才会被释放。
- 循环等待:有一组等待进程{p0, p1, p2,...pn},p0等待的资源被p1占有,p1等待的资源被p2占有,.....pn资源被p0占有。
Note: 必要条件,缺一不可。
-
C++相关
- 什么是锁?有什么作用?
在c++中,锁是一种同步工具,用于保护共享资源,防止多个线程同时访问,从而避免数据竞争和不一致 - 有哪些锁:互斥锁,自旋锁,信号量和条件变量等
- 互斥锁如何使用
C++11之前,Linux下使用pthread库中的mutex:
#include<pthread.h> pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&mutex_); ... phtread_mutex_unlock(&mutex_);
C++11之后引入了std::mutex,统一了各个平台上互斥锁的使用
#include<mutex> std::mutex mutex_; mutex_.lock(); ... mutex_.unlock();
- pthread_mutex和std::mutex有没有非阻塞的api
有的,是pthread_mutex_trylock() 和 try_lock(),当获取不到锁时这两者并不阻塞当前线程,而是立即返回,当pthread_mutex_trylock()获取到锁时返回0,而std::mutex::try_lock()方法获取不到锁时返回false - std::lock_guard 和 std::unique_lock区别
- 相同点:两者RAII技术(资源获取即初始化)
- 不同点:std::unique_lock灵活性高于std::lock_guard,前者可以在任何时间解锁和锁定,而std::lock_guard在构造时锁定,在析构时解锁,不能手动控制。所有权:std::unique_lock 支持所有权转移,而std::lock_guard不支持。性能:由于std::unique_lock灵活性较高,性能差一些
实现一个lock_guard
class lock_guard { explicit lock_guard(std::mutex &m):mutex_(m) {//当将一个参数传递给构造函数时,如果构造函数声明中使用了 explicit 关键字,则只能使用显式转换进行转换,而不能进行隐式转换。 mutex_.lock(); } ~lock_guard() { mutex_.unlock(); } private: std::mutex &mutex_; };
- 如何避免死锁:
- 避免循环等待,如果需要在业务中获取不同的锁,保证所有业务按照相同的顺序获取锁
- 使用超时锁,当锁超时,自动释放锁
- 使用try_lock,当锁被占用时,返回false并继续执行
- 锁的粒度要适中,只保护竞态数据而不是整个过程。
- 什么是锁?有什么作用?