一、线程同步
1.互斥量
(1)定义
互斥量可以保证指令的先后执行顺序,保证了指令的原子性。
互斥量(互斥锁)是最简单的线程同步方法,只有加锁/解锁两种状态。
(2)例子
2.自旋锁
使用了自旋锁的线程会反复检查锁变量是否可用。如果一个线程未请求到锁,会一直占用CPU循环等待。
优点:
- 避免了进程或线程上下文切换的开销
缺点: - 会占用CPU资源,等待时间过长则会影响其他进程。
例子
3.读写锁
对于一些临界资源可能是多读少写的。如果在读的时候也加互斥锁,那么效率就很低,因为读的时候并不会修改资源。
(1)定义
读写锁是一种特殊的自旋锁,允许多个读者同时访问资源以提高读性能,对于写操作则是互斥的。
(2)用法
4.条件变量
(1)定义
条件变量是一种相对复杂的线程同步方法。
条件变量允许线程睡眠,直到满足某种条件。当满足条件时,可以向该线程发送信号通知唤醒。
(2)生产者消费者中的应用
缓冲区满时,生产者必须等待;缓冲区空时,消费者必须等待。
生产者每生产一个产品,就唤醒可能等待的消费者;消费者每消费一个产品,就唤醒可能等待的生产者。
(3)使用方法
一般配合互斥锁一起使用,互斥锁是用来保护条件变量的。
- pthread_mutex_t mutex 创建一个互斥锁
- pthread_cond_t cond 创建一个条件变量对象
- pthread_cond_wait(&cond,&mutex) 等待
- pthread_cond_signal(&cond,mutex) 唤醒
(4)例子
二、fork创建进程
1.概述
Java等语言创建进程时底层都是使用的fork函数。
fork创建的进程初始化状态与父进程一样,系统会为fork的进程分配新的资源。
2.使用
fork系统调用无参数,fork会返回两次,分别返回子进程id和0。其中子进程id是父进程的fork返回的,0是子进程的fork返回的。
3.例子
int main(){
pid_t pid;
pid = fork();
if(pid==0){
cout << "这是一个子进程" << endl;
}else if(pid > 0){
cout << "这是一个父进程" << endl;
cout << "子进程id:" << pid << endl;
}else{
cout << "创建进程失败" << endl;
}
return 0;
}
执行结果如下,返回了两次:
三、进程同步
1.共享内存
(1)进程内存空间互相独立
进程的逻辑空间和内存中的物理空间映射,不同进程内存空间互不干扰。
在某种程度上,多进程是共同使用物理内存的。但由于操作系统的进程管理,进程间的内存空间是独立的。
(2)共享内存
共享内存可以将不同进程的逻辑页映射到同一物理块。
共享内存是两个进程之间共享和传递数据最快的方式。缺点是:共享内存未提供同步机制,需要借助其他机制管理访问。
(3)共享内存使用方法
2.Unix域套接字
(1)概念
域套接字是一种高级的进程间通信的方法,Unix域套接字可以用于同一机器进程间通信。
传统的套接字需要用于TCP/IP协议栈,Unix系统提供的域套接字提供了网络套接字类似的功能。