2022-08-17 11:36:12
浏览数 (1)
Posix 多进程
- 进程通过fork()原语进行创建,使用kill()原语进行销毁,也可使用exit()原语自我撤销。执行fork()的进程是新创建进程的父进程。父进程可以通过wait()原语等待子进程的执行完成
- fork()执行成功后一共返回2次,一次返回给父进程,另外一次返回给子进程
- fork()创建出来的进程是不会共享内存,采用了COW的策略,父子进程在只读模式下共享变量,一旦父进程或者子进程修改变量时候,在自己的进程空间中复制这个变量进行修改。
代码语言:javascript
复制#include <iostream>
#include <chrono>
#include <thread>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int x = 100;
void wait_all()
{
int pid;
int status;
for (;;)
{
pid = wait(&status);
if (pid == -1)
{
if (errno == ECHILD)
{
break;
}
perror("wait");
exit(-1);
}
}
}
int main()
{
int pid = fork();
if (pid < 0)
{
perror("fork");
exit(-1);
}
if (pid == 0)
{
std::this_thread::sleep_for(std::chrono::seconds(2));
x = 200;
std::cout << "return child process:" << getpid() << ",x=" << x << std::endl;
}
else
{
std::cout << "return parent process:" << getpid() << ",x=" << x << std::endl;
}
wait_all();
return 0;
}
Posix 多线程
- 在一个已有的进程中的创建线程需要使用pthread_create原语,多线程模型的pthread_join是对fork-join中wait()的模仿,它会阻塞到某个线程返回。
- 线程返回有两种方式,一种是pthread_exit返回;另外一种是pthread_join返回。
- 多线程模型中多个线程会共享进程之间的数据,可能存在数据竞争的情况。Posix提供了锁的机制来避免数据竞争,在Posix锁包括了几个原语,其中最基础的是pthread_mutex_init、pthread_mutex_lock和pthread_mutex_unlock。pthread_mutex_init来初始化锁,pthread_mutex_lock是用来获取锁,pthread_mutex_unlock是用来释放锁,并且这2个是相互互斥的加锁和解锁原语
- Posix API提供一种读写锁,用pthread_rwlock_t类型来表示,pthread_rwlock_rdlock原语获取pthread_rwlock_t的读锁,pthread_rwlock_ unlock来释放锁。在任意时刻,一个线程持有给定pthread_rwlock_t的写锁,但同时多个线程可以持有给定pthread_rwlock_t的读锁
- 临界区资源最小化时候互斥锁、读写锁的开销非常大,考虑到性能可以使用gcc提供的原子操作来保护这些最小化资源。
__sync_synchronize()
原语是一个内存屏障,它限制编译器和CPU对指令乱序执行的优化;在某些情况下,只限制编译器对指令优化,可以使用barrier()
原语。
并发编程工具的选择
- 在能解决问题的前提下,并发编程工具选择最简单的一个,如果可以尽量使用串行编程,如果达不到要求,使用shell脚本来实现并行化。如果shell脚本的fork/exec开销太大,可以使用GNU C的fork和wait原语。如果这些原语开销太大,可以使用Posix线程库原语,选择合适的锁机制或者原子操作