一、无名管道: pipe ---父子进程通信
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
(1). fd[2] = {0}; ---无名管道文件描述符,读 管道文件描述符:fd[0], 写 管道文件描述符:fd[1]
(2). pipe(fd); ---生成无名管道函数,返回0成功,-1失败
(3). pid_t pid = fork(); ---生成子进程函数,返回-1失败,0子进程,大于0父进程
(4). write(fd[1], buf, strlen(buf)); ---向无名管道 写 数据
wait(NULL); ---等待一个子进程退出
fcntl(fd[0], F_SETFL, O_NONBLOCK); ---设置 无名管道 不阻塞
read(fd[0], buf, sizeof(buf)); ---从无名管道 读 数据
waitpid(pid); ---等待pid子进程退出
二、有名管道:mkfifo ---非父子进程或父子进程通信
(1). if(access("../myMkfifo", F_OK) != 0) ---判断有无 ../myMkfifo 管道文件, 有返回0, 无返回-1
(2). mkfifo("../myMkfifo", 0666); ---创建有名管道文件,返回0成功,-1失败
(3). fd = open("../myMkfifo", O_WRONLY); ---打开管道文件
write(fd, buf, strlen(buf)) ---管道文件写数据,其他进程也可以 打开管道文件,读 写 数据
三、信号:signal ---通过信号 进程间通信,挂起进程、杀死进程....,SIGINT, SIGQUIT, SIGUSR1, SIGKILL等, kill -l命令查看
#include <signal.h>
(1). signal(SIGINT, signalHandler); ---改变信号SIGINT的 实现函数, 函数为 signalHandler 参数
void signalHandler(int signum)
{
if(signum == SIGINT){
printf("rcv SIGINT!\n");
}
else{
printf("rcv other signal!\n");
}
}
signal(SIGINT, SIG_DFL); ---恢复信号默认值
(2). kill(pid, SIGINT); ---向进程 pid 发送信号SIGINT
四、共享内存: shm ---
#include <sys/ipc.h>
#include <sys/shm.h>
(1). int projId = rand();
key_t key = ftok("../", projId); ---生成共享内存的键值, 返回-1失败
(2). int shmId = shmget(key, 1024, IPC_CREAT | 0666); ---创建共享内存id,大小为1024, 返回-1失败
system("ipcs -m"); ---查看共享内存
(3). char *shmAddr = shmat(shmId, NULL, SHM_RDONLY); ---将共享内存映射到进程,返回映射地址shmAddr
strcpy(shmAddr, "hello cying!\n"); ---往共享内存写数据
(4). shmdt(shmAddr); ---在进程中卸载共享内存shmAddr
(5). shmctl(shmId, IPC_RMID, NULL); ---删除共享内存id
五、消息队列: msg ---
#include <sys/msg.h>
(1). int projId = rand();
key_t key = ftok("../", projId); ---生成共享内存的键值, 返回-1
(2). int msgId= msgget(key, IPC_CREAT | 0666); ---创建消息队列id, 返回-1失败
system("ipcs -q");
(3). struct msgbuf ---消息队列通信结构体
{
long mtype; ---消息类型
char mtext[1024-sizeof(long)]; ---文本长度
};
struct msgbuf buf;
buf.mtype = 1;
strcpy(buf.mtext, "hello cherry!");
msgsnd(msgId, &buf, strlen(buf.mtext), 0); ---消息队列 数据发送, 最后一个参数msgflg(0, IPC_NOWAIT, MSG_COPY, MSG_EXCEPT, MSG_NOERROR)
int recv_len = msgrcv(msgId, &buf, sizeof(buf.mtext), 1, 0); ---数据接收,返回接收长度, 倒数第二个参数消息类型:1
(4). msgctl(msgId, IPC_RMID, NULL); ---删除消息队列id
六、system V 同步与互斥---信号量: sem ---
#include <sys/sem.h>
1> void P(int semId)
{
struct sembuf buf = {0, -1, SEM_UNDO};
int ret = semop(semId, &buf, 1);
}
void V(int semId)
{
struct sembuf buf = {0, 1, SEM_UNDO};
int ret = semop(semId, &buf, 1);
}
struct sembuf
{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */ ---IPC_NOWAIT和SEM_UNDO
};
2> system V 互斥(mutex)
(1). int projId = rand() % 255;
key_t key = ftok("../myFtok", projId);
(2). int semId = semget(key, 1, IPC_CREAT | 0666); ---创建信号集id, 信号量个数为1
system("ipcs -s");
(3). int ret = semctl(semId, 0, SETVAL, 1); ---设置arg.val 初值
(4). 父进程:
P(semId);
其他要执行的操作...;
V(semId);
子进程:
P(semId);
其他要执行的操作...;
V(semId);
(5). semctl(semId, 0, IPC_RMID);
3> system V 同步(sync)
(1). int projId = rand() % 255;
key_t key1 = ftok("../myFtok", projId);
key_t key2 = ftok("../myFtok", projId);
(2). int semId1 = semget(key1, 1, IPC_CREAT | 0666); ---创建信号集id1, 信号量个数为1
int semId2 = semget(key2, 1, IPC_CREAT | 0666); ---创建信号集id2, 信号量个数为1
system("ipcs -s");
(3). int ret = semctl(semId1, 0, SETVAL, 1);
int ret = semctl(semId2, 0, SETVAL, 0);
(4). val1 = semctl(semId_1, 0, GETVAL, 0); ---获取arg.val 的值
val2 = semctl(semId_2, 0, GETVAL, 0);
父进程:
P(semId1);
其他要执行的操作...;
V(semId2);
子进程:
P(semId2);
其他要执行的操作...;
V(semId1);
(5). semctl(semId1, 0, IPC_RMID);
semctl(semId2, 0, IPC_RMID)
七、POSIX 同步与互斥
#include <semaphore.h>
1> 互斥(mutex)
(1). sem_t *semId_1 = sem_open("sem_1", O_CREAT, 0666, 1); ---创建并打开 名为 sem_1的POSIX信号量,返回semId, arg.val初值是 0
(2). 父进程:
sem_wait(semId_1);
其他要执行的操作...;
sem_post(semId_1);
子进程:
sem_wait(semId_1);
其他要执行的操作...;
sem_post(semId_1);
(3). sem_close(semId_1); ---关闭semId
(4). sem_unlink("sem_1"); ---卸载sem_1
2> 同步(sync)
(1). sem_t *semId_1 = sem_open("sem_1", O_CREAT, 0666, 1);
sem_t *semId_2 = sem_open("sem_2", O_CREAT, 0666, 0);
sem_init(semId_1, 1, 1); ---初始化semId, 第二个参数为 0 时,在进程与线程间通信, 第二个参数非 0 时,在进程与进程间通信,第三个参数是 arg.val的值
sem_init(semId_2, 1, 0);
(2).sem_getvalue(semId_1,&val1); ---获取arg.val
sem_getvalue(semId_2,&val2);
父进程:
sem_wait(semId_1);
其他要执行的操作...;
sem_post(semId_2);
子进程:
sem_wait(semId_2);
其他要执行的操作...;
sem_post(semId_1);
(3). sem_close(semId_1);
sem_close(semId_2);
(4). sem_unlink("sem_1");
sem_unlink("sem_2");
僵尸进程处理
(1)//singal(SIGCHLD, SIG_IGN); //忽略子进程结束发给父进程的SIGCHLD信号
(2)signal(SIGCHLD, sigchld_handler);
void sigchld_handler(int sig)
{
//wait(NULL); //只能处理一个进程
while(waitpid(-1, NULL, WNOHANG) > 0) //推荐:处理所有进程
;
}