并行程序设计

本文探讨了Linux进程管理的核心命令PS,进程创建的fork函数,进程替换的exec函数族,以及线程的创建、通信和同步机制。涵盖了守护进程、进程状态、线程特点和通信手段,适合理解进程和线程在系统中的运作原理。
摘要由CSDN通过智能技术生成

进程命令 PS

Ps axu(打印所有进程信息)

程序

存放在磁盘上的指令和数据的有序集合(静态的)

进程

执行一个程序所分配的资源的总称

进程是程序的一次执行过程

动态的,包括创建、调度、执行和死亡

进程类型

交互进程:在shell下启动,可以在前台运行,也可以在后台运行

批处理进程:和在终端无关,被提交到一个作业队列中以便顺序执行

守护进程:和终端无关,一直在后台运行

进程状态

运行态:进程正在运行,或者准备运行

等待态:进程在等待一个事件的发生或某种系统资源(可中断、不可中断)

停止态:进程被终止,收到信号后可继续运行

死亡态:已终止的进程,但pcb没有被释放

查看进程信息

PS 查看系统进程快照

Top 查看进程动态信息

/proc 查看进程详细信息

Nice 按用户指定的优先级运行进程

Renice 改变正在运行进程的优先级

Jobs 查看后台进程

bg 将挂起的后台进程在后台运行

Fg把后台运行的进程放到前台运行

进程创建-fork

#include<unistd.h>

Pid_t fork(void)

创建新的进程,失败时返回-1

成功时父进程返回子进程的进程号,子进程返回0

通过fork的返回值区分父进程和子进程

父子进程

子进程继承了父进程的内容

父子进程有独立的地址空间,互不影响

若父进程先结束

  1. 子进程成为孤儿进程,被init进程收养
  2. 子进程变成后台进程

若子进程先结束

父进程如果没有及时回收,子进程变成僵尸进程。

子进程从何处开始运行?

子进程从fork后开始运行,不是从main开始

父子进程谁先执行?

父子进程谁先运行依赖于操作系统调度策略,不确定

父进程能否多次调用fork?子进程呢?

都可以

进程结束-exit/_exit

#include<stdlib.h>

#include<unistd.h>

Void exit(int status);

Void _exit(int status);

结束当前的进程并将status返回

Exit结束进程时会刷新(流)缓冲区

进程回收

子进程结束时由父进程回收

孤儿进程由init进程回收

若没有及时回收会出现僵尸进程

进程回收-wait

#include<unistd.h>

pid_t wait(int *status);

成功时返回回收的子进程的进程号;失败时返回EOF

若子进程没有结束,父进程一直阻塞

若有多个子进程,哪个先结束就先回收

Status指定保存子进程返回值和结束方式的地址

Status为NULL 表示直接释放子进程PCB,不接受返回值

子进程通过exit/_exit/return返回某个值(0-255)

父进程调用wait(&status)回收

WIFEXITED(status)判断子进程是否正常结束

WEXITSTATUS(status)获取子进程返回值

WIFSIGNALED(status)判断子进程是否被信号结束

WIERMSIG(status)获取结束子进程的信号类型

进程回收-waitpid

#include <unistd.h>

Pid_t waitpid(pid_t pid,int *status,int option);

成功时返回回收的子进程的pid或0;失败时返回EOF

Pid可用于指定回收哪个子进程或任意子进程

Status指定用于保存子进程返回值和结束方式的地址

Option指定回收方式,0或WNOHANG

进程-exec函数族

进程调用exec函数族执行某个程序

进程当前内容被指定的程序替换

实现让父子进程执行不同的程序

  1. 父进程创建子进程
  2. 子进程调用exec函数族
  3. 父进程不受影响

#include<unistd.h>

Int execl(const char *path,const char *arg,...);

Int execlp(const char *file,const char *arg,...);

成功时执行指定的程序;失败时返回EOF

Path执行的程序名称,包含路径

Arg...传递给执行的程序的参数列表

File 执行的程序的名称,在path中查找

#include<unistd.h>

Int execv(const char *path,char *const argv[])

Int execvp(const char *file,char *const argv[]);

成功时执行指定的程序;失败时返回EOF

Arg...封装成指针数组的形式

#include<stdlib.h>

Int system(const char *command);

成功时返回命令command的返回值;失败时返回EOF

当前进程等待command执行结束后才继续执行。

守护进程

守护进程(Daemon)是Linux三种进程类型之一

通常在系统启动时运行,系统关闭时关闭

Linux系统中大量使用,很多服务程序以守护进程形式运行

守护进程特点:

始终在后台运行

独立于任何终端

周期性的执行某种任务或等待处理特定事件

守护进程-会话、控制终端

Linux以会话(session)、进程组的方式管理进程

每个进程属于一个进程组

会话是一个或多个进程组的集合。通常用户打开一个终端时,系统会创建一个会话。所有通过该终端运行的进程都属于这个会话

终端关闭时,所有相关进程都被结束

创建守护进程(一)

创建子进程,父进程退出

if(fork()>0){

Exit(0);

}

子进程变成孤儿进程,被init进程收养

子进程在后台运行

创建守护进程(二)

子进程创建新会话

If(setsid()<0){

Exit(-1);

}

子进程成为新的会话组长

子进程脱离原先的终端

创建守护进程(三)

更改当前工作目录

Chdir(“/”);

Chdir(“/tmp”);

守护进程一直在后台运行,其工作目录不能被卸载

重新设定当前工作目录cwd

创建守护进程(四)

重设文件权限掩码

If(umask(0)<0){

Exit(-1);

}

文件权限掩码设置为0;

只影响当前进程

创建守护进程(五)

关闭打开的文件描述符

Int i;

For(i=0,i<gettablesize();i++){

Close(i);

}

关闭所有从父进程继承的打开方式

已脱离终端,stdin/stdout/stderr无法再使用

进程

进程有独立的地址空间,Linux为每个进程创建task_struct,每个进程都参与内核调度,互不影响。

线程

进程在切换时系统开销大,很多操作系统引入了轻量级进程LWP,同一进程中的线程共享相同地址空间,Linux不区分进程、线程。

线程特点

通常线程指的是共享相同地址空间的多个任务

使用多线程的好处

大大提高了任务切换的效率,避免了额外的TLB & cache的刷新

线程共享资源

一个进程中的多个线程共享以下资源:

可执行的指令、静态数据、进程中打开的文件描述符、当前工作目录,用户ID、用户组ID

每个线程私有的资源包括:

线程ID(TID)、PC(程序计数器)和相关寄存器、堆栈、错误号(errno)、优先级、执行状态和属性。

Linux线程库

Pthread线程库提供了如下基本操作:

创建线程、回收线程、结束线程

同步和互斥机制

信号量、互斥锁

线程创建-pthread_create

#include<pthread.h>

Int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*routine)(void *),void *arg);

成功返回0,失败时返回错误码

Thread线程对象

Attr 线程属性,NULL 代表默认属性

Routine线程执行的函数

arg 传递给routine的参数 ,参数是void * ,注意传递参数格式

Pthread_t pthread_self(void) 查看自己的TID。

线程回收-pthread_join

#include <pthread.h>

Int pthread_join(pthread_t thread,void **retval);

成功返回0,失败时返回错误码

Thread要回收的线程对象

调用线程阻塞直到thread结束

*retval接受线程thread的返回值

Ps -eLf|grep cthread  //查看线程

Ps -ef|grep pthread  //查看进程

线程结束-pthread_exit

#include <pthread.h>

Void pthread_exit(void *retval);

结束当前线程

Retval可被其他线程通过pthread_join获取

线程私有资源被释放

线程间通信

线程共享同一进程的地址空间

优点:线程间通信很容易,通过全局变量交换数据

缺点:多个线程访问共享数据时需要同步或互斥机制

线程通信—同步

同步(synchronization)指的时多个任务按照约定的先后次序相互配合完成一件事情

由信号量来决定线程是继续运行还是阻塞等待

信号量(灯)

信号量代表某一类资源,其值代表系统中该资源的数量

信号量是一个受保护的变量,只能通过三种操作来访问

初始化

P操作(申请资源)

V操作(释放资源)

信号量—P/V操作

P(S)含义如下:

if(信号量的值大于0){申请资源的任务继续运行;信号量的值减一:}

Else{申请资源的任务受阻}

V(S)含义如下:

信号量的值加一;

If(有任务在等待资源){唤醒等待的任务,让其继续运行}

线程通信-互斥

临界资源

一次只允许一个任务(进程,线程)访问的共享资源

临界区

访问临界区的代码

互斥机制

Mutex互斥锁

任务访问临界资源前申请锁,访问完后释放锁。

无名管道特点

无名管道具有如下特点:

只能用于具有血缘关系的进程之间的通信

单工的通信模式,具有固定的读端和写端

无名管道创建时会返回两个文件描述符,分别用于读写管道

有名管道特点:

对应管道文件,可用于任意进程之间进行通信

打开管道时可指定读写方式

通过文件IO操作,内容存放在内存中。

信号机制

信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。

Linux内核通过信号通知用户进程,不同的信号类型代表不同的事件

Linux对早期的unix信号机制进行了扩展

进程对信号有不同的响应方式

缺省方式

忽略信号

捕捉信号

信号相关命令kill/killall

Kill[-signal]pid

默认发送SIGTERM

-sig可指定信号

Pid 指定发送对象

Killall[-u user|prog]

prog 指定进程名

User 指定用户名

SIGHUP(该信号在用户终端关闭时产生,通常是发给和该终端关联的会话内的所有进程)

SIGINT(该信号在用户键入INTR字符(Ctrl-C)时产生,内核发送此信号送到当前终端的所有前台进程)

SIGQUIT(该信号和SIGINT类似,但由QUIT字符(通常是Ctrl-\)来产生)

SIGILL(该信号在一个进程企图执行一条非法指令时产生)

SIGSEV(该信号在非法访问内存时产生,如野指针、缓冲区溢出)

SIGPIPE(当进程往一个没有读端的管道中写入时产生,代表“管道断裂”)

SIGKILL(该信号用来结束进程,并且不能被捕捉和忽略)

SIGSTOP(该信号用于暂停进程,并且不能被捕捉和忽略)

SIGTSTP(该信号用于暂停进程,用户可键入SUSP字符(通常是Ctrl-Z)发出这个信号)

SIGCONT(该信号让进程进入运行态)

SIGALRM(该信号用于通知进程定时器时间已到)

SIGUSR1/2(该信号保留给用户程序使用)

System V IPC

IPC对象包括:共享内存、消息队列和信号灯集

每个IPC对象有唯一的ID

IPC对象创建后一直存在,直到被显式的删除

每个IPC对象有一个关联的KEY

Ipcs/ipcrm

共享内存

共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝

共享内存在内核空间创建,可被进程映射到用户空间访问,使用灵活

由于多个进程可同时访问共享内存,因此需要同步和异步机制配合使用。

共享内存使用步骤:

创建/打开共享内存

映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问

读写共享内存

撤销共享内存映射

删除共享内存映射

消息队列

消息队列是System V IPC对象的一种

消息队列由消息队列ID来唯一标识

消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等。

消息队列可以按照类型来发送/接收消息

消息队列使用步骤

打开/创建消息队列 msgget

向消息队列发送消息 msgsnd

从消息队列接收消息 msgrcv

控制消息队列 msgctl

消息格式

通信双方首先定义好统一的消息格式。

用户根据应用需求定义结构体类型。

首成员类型必须为long,代表消息类型(正整数)。

其他成员都属于消息正文。

消息长度不包括首类型long。

System V IPC-信号灯

信号灯也叫信号量,用于进程/线程同步或互斥的机制

信号灯的类型

Posix无名信号灯

Posix有名信号灯

System V 信号灯

信号灯的含义

计数信号灯

System V IPC

System V信号灯是一个或多个计数信号灯的集合

可同时操作集合中的多个信号灯

申请多个资源时避免死锁

System V信号灯使用步骤

打开/创建信号灯 semget

信号灯初始化 semctl

P/V操作 semop

删除信号灯 semctl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值