并发


并发

进程

命令

ps -ef显示系统中所有进程信息

ps aux比ps -ef多显示当前进程状态

top每隔3秒刷新所有进程状态等信息

进程详细信息在/proc中

nice -n 优先级(-209,数字越小优先级越低,仅可修改为09) 进程:更改进程优先级,renice改变已有进程优先级

fg可让进程从后台运行改为前台运行

函数

创建

需要引用unisd.h

pid_t fork(void);失败会返回-1,成功父进程会返回子进程的进程号,子进程返回0

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

getpid()获取进程pid

父进程先结束,子进程会变成孤儿进程被init进程收养,子进程变成后台进程

子进程先结束,父进程没有及时回收子进程会变成僵尸进程(要避免)

子进程在fork语句后执行

结束

需要引用unisd.h和stdlib.h

void exit(int status);

void _exit(int status);

结束进程后会将status返回

exit结束进程时会刷新缓冲区,_exit会丢弃缓冲区数据

exec函数族

需要引用unisd.h

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

让父子进程执行不同程序

int execl(const char *path, const char *arg, 。。。);

int execlp(const char *file, const char *arg, 。。。);

成功执行指定程序,失败返回EOF

path执行程序名称和路径

arg。。。传递给执行程序的参数列表,最后一个一定要是NULL

file执行程序名称,在PATH中查找

int execv(const char *path, char *const argv[]);

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

成功执行指定程序,失败返回EOF

arg。。。封装成指针数组,同样最后一个参数为NULL

需要引用stdlib.h

int system(const char *command);

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

回收

子进程由父进程回收

孤儿进程由init进程回收

没有及时回收会变成僵尸进程

需要引用unisd.h

pid_t wait(int *status);

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

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

多个子进程哪个先结束哪个先回收

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

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

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

成功返回子进程的pid或0,失败返回EOF

pid指定回收哪个子进程或者任意子进程(-1)

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

option指定回收方式,0(阻塞)或WNOHANG(非阻塞)

守护进程(Daemon)

系统启动时运行,系统关闭时结束

linux很多服务程序以守护进程形式运行

后台运行,独立于任何终端

周期性执行某种任务

会话是一个或多个进程组的集合,每个进程都属于一个进程组

创建

子进程创建,父进程退出变成孤儿进程被init进程收养后台运行

子进程创建新会话变成新会话的组长,这样就脱离了原先的终端

更改当前工作目录

守护进程一直在后台运行,工作目录不能被卸载,重新设定当前工作目录cwd

重设文件权限掩码,文件权限掩码设置为0,只影响当前文件

关闭当前的文件描述符,关闭所有从父进程继承的打开的文件

线程

进程有独立的地址空间

每个进程都参与内核调度,互不影响

进程在切换时系统开销大

轻量级进程LWP为线程

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

创建

需要引入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的参数

回收

需要引入pthread.h

int pthread_join(pthread_t thread, void **retval);成功返回0,失败返回错误码

thread要回收的线程对象

调用线程阻塞直到thread结束

*retval接收线程的返回值

void pthread_exit(void *retval);

结束当前线程

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

线程私有资源会被释放

信号量

有名信号量既可以用在进程之间也可以用在线程之间

需要引用semaphore.h

int sem_init(sem_t *sem, int pshared, unsigned int value);

成功返回0,失败返回EOF

sem指向要初始化的信号量对象

pshared 0线程间 1进程间

val信号量初始值

int sem_wait(sem_t *sem);P操作

int sem_post(sem_t *sem);V操作

成功返回0,失败返回EOF

sem指向要操作的信号量对象

互斥

临界资源:一次只允许一个任务访问的共享资源

临界区

互斥机制:任务访问临界资源前先申请锁,访问完释放锁

​ mutex互斥锁

互斥锁

初始化

需要引入pthread.h

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

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

mutex指向要初始化的互斥锁对象

如果无法获得锁就阻塞任务

释放锁

int pthread_mutex_unlock(pthread_mutex_t *mutex);

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

mutex指向要初始化的互斥锁对象

执行完临界区要及时释放锁

进程间通信

无名管道

只能用于有亲缘关系的进程间

单工通信模式,单向

创建

需要引用unisd.h

int pipe(int pfd[2]);

成功返回0,失败返回EOF(-1)

pfd包含两个元素的整形数组,用于保存文件描述符

pfd[0]用于读管道, pfd[1]用于写管道

需要在创建进程前创建管道

文件一旦读走就不存在了

当管道中数据量大于读端定义的大小只会读定义的大小对应的数据,否则全读

如果管道中无数据就返回0

当空间不足时,会先写满空间然后阻塞写端

当读端不存在不会写入管道,这种情况叫管道断裂,对应的信号是13/d

有名管道

需要引用unisd.h和fcntl.h

int mkfifo(const char *path, mode_t mode);

成功返回0,失败返回EOF

path创建管道文件路径

mode管道文件的权限,如0666

管道程序永远是0

必须同时有读端和写端才可以正常运行,否则直接阻塞

信号

kill -9 -1 很危险,给系统中所有程序发信号

需要引用unisd.h和signal.h

int kill(pid_t pid, int sig);

int raise(int sig);给自己发信号

成功返回0,失败返回EOF

pid接收进程的进程号,0代表同组进程,-1代表所有进程

sig信号类型

int alarm(unsigned int seconds);定时器(经常用于超时检测)

成功返回上一个定时器的剩余时间,失败返回EOF

seconds定时器时间,如果为0代表取消当前定时器

一个进程只能设定一个定时器,时间到时产生SIGALRM

int pause(void);让进程睡眠

进程一直被阻塞,直到被信号中断

被信号中断后返回-1,errno为EINTR

设置信号响应方式

需要引用unisd.h和signal.h

void (*signal(int signo, void (*handler)(int)))(int);

成功返回原先的信号处理函数,失败返回SIG_ERR

signo设置的信号类型

handler指定的信号处理函数, SIG_DFL代表缺省方式, SIG_IGN代表忽略信号

IPC

需要引用sys/types.h和sys/ipc.h

key_t ftok(const char *path, int proj_id);

成功返回合法的key值,失败返回EOF

path存在且可访问的文件的路径

proj_id用于生成key的数字,不能为0

共享内存

创建

需要引用sys/shm.h和sys/ipc.h

int shmget(key_t key, int size, int shmflg);

成功返回共享内存id,失败返回EOF

key是和共享内存关联的key,由IPC_PRIVATE(私有)或ftok生成的地址

shmflg共享内存标志位IPC_CREAT(私有可以没有IPC_CREAT)|0666

映射

需要引用sys/shm.h和sys/ipc.h

void *shmat(int shmid, const void *shmaddr, int shmflg);映射后可像访问正常地址一样访问

成功返回映射后的地址,失败返回(void *)-1

shmid要映射的共享内存id

shmaddr映射后的地址,NULL由系统自动映射

shmflg标志位, 0表示可读写,SHM_RDONLY表示只读

撤销映射

需要引用sys/shm.h和sys/ipc.h

int shmdt(void *shmaddr);

成功返回0,失败返回EOF

不使用共享内存时应及时撤销映射,进程结束系统会自动撤销

控制

需要引用sys/shm.h和sys/ipc.h

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

成功返回0,失败返回EOF

shmid要操作的共享内存id

cmd要执行的操作IPC_STAT(获取共享内存属性) IPC_SET(设置共享内存属性) IPC_RMID(删除共享内存id,buf可设置为NULL)

buf结构体指针,保存或设置共享内存属性的地址

ipcs -l查看共享内存大小等信息

cat /proc/sys/kernel/shmmax设定共享内存大小等信息

shmctl仅添加标记,当所有映射该共享内存的进程都取消映射后再删除,nattach记录映射该共享内存的进程数

消息队列(和共享内存函数有一定的相似度)

创建/打开

需要引用sys/msg.h和sys/ipc.h

int msgget(key_t key, int msgflg);

成功返回消息队列id,失败返回EOF

key是和消息队列关联的key,由IPC_PRIVATE(私有)或ftok生成的地址

msgflg标志位 IPC_CREAT(私有可以没有IPC_CREAT)|0666

发送消息

需要引用sys/msg.h和sys/ipc.h

int msgsnd(int msgid, const void *msgp, size_t size, int msgflg);

成功返回0,失败返回-1

msgid消息队列id

msgp消息缓冲区地址

size消息正文长度

msgflg标志位 0或IPC_NOWAIT(不论消息是否发送成功都返回)

接收消息

需要引用sys/msg.h和sys/ipc.h

int msgrcv(int msgid, const void *msgp, size_t size, long msgtype, int msgflg);

成功返回收到的消息长度,失败返回-1

msgid消息队列id

msgp消息缓冲区地址

size接收的消息长度

msgtype指定接收的消息类型 0为接收最早的消息

msgflg标志位 0或IPC_NOWAIT(不论消息是否接收成功都返回,不成功返回错误)

控制消息队列

需要引用sys/msg.h和sys/ipc.h

int msgctl(int msgid, int cmd, struct msqid_ds *buf);

成功返回0,失败返回-1

msgid消息队列id

cmd要执行的操作 IPC_STAT/IPC_SET/IPC_RMID

System V 信号灯

创建/打开

需要引用sys/sem.h和sys/ipc.h

int semget(key_t key, int nsems, int semflg);

成功返回信号灯id,失败返回-1

key是和消息队列关联的key,由IPC_PRIVATE(私有)或ftok生成的地址

nsems集合中包含的计数信号灯个数

semflg标志位 IPC_CREAT|0666 | IPC_EXCL(检查对象是否存在)

初始化

需要引用sys/sem.h和sys/ipc.h

int semctl(int semid, int semnum, int cmd, …);

成功返回0,失败返回EOF

semid要操作的信号灯集id

semnum要操作的集合中的信号灯编号

cmd执行的操作 SETVAL(需要加第四个参数union semun) IPC_RMID

union semun(需要自己定义)取决于cmd

P/V操作

需要引用sys/sem.h和sys/ipc.h

int semop(int semid, struct sembuf *sops, unsigned nsops);

成功返回0,失败返回-1

semid要操作的信号灯集id

sops描述对信号灯操作的结构体(数组)

nsops要操作的信号灯个数

struct sembuf

{

​ short semnum;

​ short sem_op;

​ short sem_flg;

}

semnum信号灯编号

sem_op:-1-P操作/1-V操作

sem_flg:0/IPC_NOWAIT


文章作者: hhs1231
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hhs1231 !
评论
  目录