文章目录
一、管道
无名管道
pipe.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
//int pipe(int fd[2]); // 返回值:若成功返回0,失败返回-1
int main()
{
int fd[2];
int ret;
pid_t PID;
int n_read;
int n_write;
char *buf= (char*)malloc(128);
//创建无名管道
if ( (ret = pipe(fd)) == -1 )
{
printf("create pipe failed\n");
return -1;
}
//创建子进程
PID = fork();
//father process write string
if( PID > 0)//父进程
{
close(fd[0]);// 关闭读端
n_write = write(fd[1],"hello boy from father",strlen("hello boy from father"));//开启写端,写入管道
printf("write %d byte success\n",n_write);
wait(NULL);
}
else if(PID == 0)
{
//son process read string
close(fd[1]);//关闭写端
n_read = read(fd[0],buf,128);//读管道消息
printf("read:%d byte,content:%s\n",n_read,buf);
exit(0);
}else
{
printf( "creat fork failed\n");
return -1;
}
free(buf);
return 0;
}
效果截图
有名管道
1.fifo_write.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
//int pipe(int fd[2]); // 返回值:若成功返回0,失败返回-1
int main()
{
int fd;
int n_read;
int n_write;
char *buf = "you are a handsomeboy";
//create fifo file
printf("Please create file\n");
if (mkfifo("./file",0600)== -1 && errno != EEXIST)
{
puts("mkfifo failed\n");
return -1;
}
//open file
fd = open("./file",O_WRONLY);
if(fd == -1)
{
perror("why");
return -1;
}
//write file
while(1)
{
n_write = write(fd,buf,strlen(buf));
sleep(1);
}
return 0;
}
2.fifo_read.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
//int pipe(int fd[2]); // 返回值:若成功返回0,失败返回-1
int main()
{
int fd;
int n_read;
char buf[1024] = {0};
//create fifo file
if( mkfifo("./file",0600) == -1 && errno != EEXIST)
{
puts("creat mkfifo failed\n");
return -1;
}
//open file
fd = open("./file",O_RDONLY);
if(fd == -1)
{
perror("why");
return -1;
}
//read file
while(1)
{
n_read = read(fd,buf,1024);
printf("read %d byte,content:%s\n",n_read,buf);
sleep(2);
}
return 0;
}
效果截图
二、消息队列
1.msg_snd.c
#include <sys/msg.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
/*
2 // 创建或打开消息队列:成功返回队列ID,失败返回-1
3 int msgget(key_t key, int flag);
4 // 发送消息:成功返回0,失败返回-1
5 int msgsnd(int msqid, const void *ptr, size_t size, int flag);
6 // 接收消息:成功返回消息数据的长度,失败返回-1
7 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
8 // 控制消息队列:成功返回0,失败返回-1
9 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
*/
struct Msg
{
long mtype;
char mtext[128];
};
int main()
{
struct Msg sendbuf = { 888,"hello poorguy do you see me?" };
key_t key;
key = ftok(".",100);
int msqid;
int ret;
int cnt = 5;
msqid = msgget(key,IPC_CREAT|0777);
if(msqid == -1)
{
printf("msgget failed\n");
return -1;
}
while(1)
{
ret = msgsnd(msqid,&sendbuf,sizeof(sendbuf.mtext),888);
if(ret == -1)
{
printf("recevied faile\n");
return -1;
}
sleep(1);
}
/*
ret = msgrcv(msqid,&readbuf,sizeof(readbuf.mtext),888,0);
if(ret == -1)
{
printf("recevied faile\n");
return -1;
}
*/
msgctl(msqid, IPC_RMID, NULL);
return 0;
}
2.msg_rcv.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdio.h>
/*
2 // 创建或打开消息队列:成功返回队列ID,失败返回-1
3 int msgget(key_t key, int flag);
4 // 发送消息:成功返回0,失败返回-1
5 int msgsnd(int msqid, const void *ptr, size_t size, int flag);
6 // 接收消息:成功返回消息数据的长度,失败返回-1
7 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
8 // 控制消息队列:成功返回0,失败返回-1
9 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
*/
struct Msg
{
long mtype;
char mtext[128];
};
int main()
{
struct Msg readbuf;
key_t key;
key = ftok(".",100);
int msqid;
int ret;
int cnt = 5;
msqid = msgget(key,IPC_CREAT|0777);
if(msqid == -1)
{
printf("msgget failed\n");
return -1;
}
while(1)
{
ret = msgrcv(msqid,&readbuf,sizeof(readbuf.mtext),888,0);
if(ret == -1)
{
printf("recevied faile\n");
return -1;
}
printf("From msgque content:%s\n",readbuf.mtext);
sleep(1);
}
msgctl(msqid,IPC_RMID,NULL);
return 0;
}
效果截图
三、共享内存
1.shm_write.c
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
/*
2 // 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
3 int shmget(key_t key, size_t size, int flag);
4 // 连接共享内存到当前进程的地址空间(也叫挂载、映射):成功返回指向共享内存的指针,失败返回-1
5 void *shmat(int shm_id, const void *addr, int flag);
6 // 断开与共享内存的连接:成功返回0,失败返回-1
//注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。
7 int shmdt(void *addr);
8 // 控制共享内存的相关信息:成功返回0,失败返回-1
9 int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
*/
int main()
{
int shm_id;
key_t key = ftok(".",100);
char *shm_addr;
int shmdt_t;
//创建获取共享内存shmget
shm_id = shmget(key,1024*4,IPC_CREAT | 0600);
if(shm_id == -1)
{
printf("creat shmget failed\n");
return -1;
}
//连接共享内存shmat
shm_addr = shmat(shm_id,0,0);
//写数据存入共享内存shmmdt
strcpy(shm_addr,"From share memory message: hello poorguy");
sleep(10);
//断开连接shmdt
shmdt_t = shmdt(shm_addr);
if( shmdt_t == -1 )
{
printf("close shmdt failed\n");
}
//销毁共享内存shmctl
shmctl(shm_id,IPC_RMID,0);
return 0;
}
2.shm_read.c
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
/*
2 // 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
3 int shmget(key_t key, size_t size, int flag);
4 // 连接共享内存到当前进程的地址空间(也叫挂载、映射):成功返回指向共享内存的指针,失败返回-1
5 void *shmat(int shm_id, const void *addr, int flag);
6 // 断开与共享内存的连接:成功返回0,失败返回-1
//注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。
7 int shmdt(void *addr);
8 // 控制共享内存的相关信息:成功返回0,失败返回-1
9 int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
*/
int main()
{
int shm_id;
key_t key = ftok(".",100);
char *shm_addr;
int shmdt_t;
//创建获取共享内存shmget
shm_id = shmget(key,1024*4,IPC_CREAT | 0600);
if(shm_id == -1)
{
printf("creat shmget failed\n");
return -1;
}
//连接共享内存shmat
shm_addr = shmat(shm_id,0,0);
//从共享内存中读取数据
printf("As follow:\n%s\n",shm_addr);
//断开连接shmdt
shmdt_t = shmdt(shm_addr);
if( shmdt_t == -1 )
{
printf("close shmdt failed\n");
}
//销毁共享内存shmctl
shmctl(shm_id,IPC_RMID,0);
return 0;
}
效果截图
四、信号
信号处理的三种方式:忽略,捕捉和默认动作。
忽略:就跟字面意思一样忽略掉它(注意:SIGKILL,SIGSTOP不能被忽略)
捕捉:就是一些信号处理的函数,然后让这个函数告诉内核,当信号产生时,内核调用该函数,实现某种信号的处理
默认动作:每个信号都有其对应的默认的处理动作,当触发了某种信号,系统就会立刻去执行。
1.捕捉ctr+c信号
signal.c
#include <signal.h>
#include <stdio.h>
// typedef定义了一种类型sighandler_t
//typedef void (*sighandler_t)(int);//函数指针(指向函数的指针),无返回值,传入参数为一个int型
//sighandler_t signal(int signum, sighandler_t handler);
// 返回这种类型 带有_t表示结构体 函数指针变量
void Handler(int signum)
{
switch(signum)
{
case 2:
printf("receive SIGINT,signum = %d\n",signum);
break;
case 9:
printf("receive SIGKILL,signum = %d\n",signum);
break;
case 20:
printf("receive SIGUSR1,signum = %d\n",signum);
break;
}
printf("never quit");
}
int main()
{
signal(SIGINT,Handler);
signal(SIGKILL,Handler);
signal(SIGTSTP,Handler);
while(1);
return 0;
}
效果截图
2.给指定的进程发送信号(把该进程杀死SIGKILL)
signal2.c
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
// typedef定义了一种类型sighandler_t
//typedef void (*sighandler_t)(int);//函数指针(指向函数的指针),无返回值,传入参数为一个int型
//sighandler_t signal(int signum, sighandler_t handler);
// 返回这种类型 带有_t表示结构体 函数指针变量
int main(int argc,char **argv[])
{
//三个参数kill -9 33550
int signum;
int pid;
char cmd[128];
signum = atoi(argv[1]);
pid = atoi(argv[2]);
//信号发送
sprintf(cmd,"kill -%d %d",signum,pid);
system(cmd);
printf("发送指令信号成功\n");
return 0;
}
3. 信号发送携带消息
收发信号
sig_send.c
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
/*struct sigaction
{ //凡是带有_t说明是个结构体
void (*sa_handler)(int);//信号处理程序,不接受额外数据,和signal()的参数handler一样(SIG_IGN 为忽略,SIG_DFL 为默认动作)
void (*sa_sigaction)(int, siginfo_t *, void *);//信号处理程序,能够接受额外数据和sigqueue配合使用
sigset_t sa_mask;//阻塞关键字的信号集(默认阻塞),可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。
int sa_flags;//配置为SA_SIGINFO这个宏表示能够接受数据
void (*sa_restorer)(void);
};*/
/*union sigval
{
int sival_int;
void *sival_ptr; 发送字符的话把地址传进来
};*/
/*
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
//sigactio(),会依照参数signum指定的信号编号来设置该信号的处理函数
//const struct sigaction *act,你要做什么
//struct sigaction *oldact,是否备份,不备份用NULL
*/
int main(int argc,char *argv[])
{
//信号类型/信号源
int signum = atoi(argv[1]);
int pid = atoi(argv[2]);
//要发送的数据可以是整数也可以是字符
union sigval value;
value.sival_int = 67;
//发送消息函数sigqueue
sigqueue(pid,signum,value);
printf("my_pid = %d\n",getpid());
printf("发送完毕\n");
return 0;
}
sig_rcv.c
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
/*struct sigaction
{ //凡是带有_t说明是个结构体
void (*sa_handler)(int);//信号处理程序,不接受额外数据,和signal()的参数handler一样(SIG_IGN 为忽略,SIG_DFL 为默认动作)
void (*sa_sigaction)(int, siginfo_t *, void *);//信号处理程序,能够接受额外数据和sigqueue配合使用
sigset_t sa_mask;//阻塞关键字的信号集(默认阻塞),可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。
int sa_flags;//配置为SA_SIGINFO这个宏表示能够接受数据
void (*sa_restorer)(void);
};*/
/*union sigval
{
int sival_int;
void *sival_ptr; 发送字符的话把地址传进来
};*/
/*
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
//sigactio(),会依照参数signum指定的信号编号来设置该信号的处理函数
//const struct sigaction *act,你要做什么
//struct sigaction *oldact,是否备份,不备份用NULL
*/
void handler(int signum, siginfo_t *info, void * context)
{
printf("signum = %d\n",signum);
if( context != NULL )
{
printf("信号源pid = %d\n",info->si_pid);
printf("get data: %d\n",info->si_int);
printf("get data: %d\n",info->si_value.sival_int);
}
}
int main(int argc,char *argv[])
{
struct sigaction act;
printf("my_pid=%d\n",getpid());
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO;//能够获取到信息的标志
//接收数据
sigaction(SIGUSR1,&act,NULL);//第三个是参数是备份的这边写NULL SIGUSR1对应的编号为10!!!SIGUSR1为用户自定义信号,
while(1);
return 0;
}
效果截图
五、信号量
函数解析
信号量编程代码如下:
sem_pv.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <unistd.h>
/*
2 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
3 int semget(key_t key, int num_sems, int sem_flags);
4 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5 int semop(int semid, struct sembuf semoparray[], size_t numops);
6 // 控制信号量的相关信息
7 int semctl(int semid, int sem_num, int cmd, ...);
*/
//semctl函数第三个参数cmd的宏要求后面定义一个联合体
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
void pGetKey(int sem_id)//P操作(拿锁)
{
struct sembuf sem_set;
sem_set.sem_num = 0;//信号量编号,每把钥匙都有特点编号,这里只有一把锁(也就是第一个信号量)
sem_set.sem_op = -1;//拿锁(-1表示P操作)
sem_set.sem_flg = SEM_UNDO; //SEM_UNDO设置为当进程结束的时候,系统自动释放该进程未释放的信号量
//进行PV操作
semop(sem_id,&sem_set,1);//“1”代表第二个参数的个数
printf("锁被拿\n");
}
void vPutBackKey(int sem_id)//v操作(放回钥匙)
{
struct sembuf sem_set;
sem_set.sem_num = 0;
sem_set.sem_op = 1;//(1表示P操作)
sem_set.sem_flg = SEM_UNDO;//进程结束,释放信号量
//进行PV操作
semop(sem_id,&sem_set,1);
printf("已放回锁\n");
}
int main()
{
key_t key = ftok(".",2);
int sem_id;
int pid;
union semun init_sem;
init_sem.val = 0;//初始是没有钥匙的状态
//1.创建信号量组
sem_id = semget(key,1,IPC_CREAT|0666 );
//2.控制信号量的相关信息
//int semctl(int semid, int sem_num, int cmd, ...);
semctl(sem_id,0,SETVAL,init_sem);
//3.执行操作(拿锁放锁操作)
pid = fork();
if(pid > 0)//父进程“拿锁”,拿锁之后放锁
{
pGetKey(sem_id);//开锁
printf("我是父进程,我要拿锁进房间\n");
vPutBackKey(sem_id);//开锁之后把钥匙放回去
semctl(sem_id,0,IPC_RMID);//销毁这个锁
}else if(pid == 0)//子进程放锁,不拿锁
{
printf("我是子进程,我要把锁放回盒子\n");
vPutBackKey(sem_id);
}else
{
printf("fork error\n");
}
return 0;
}
效果截图