目录:
-
- 文件相关命令
- 进程相关命令
-
- [getpid(); fork(); vfork();](#getpid(); fork(); vfork();)
- [exit(6);wait(status); WEXITSTATUS(status);](#exit(6);wait(status); WEXITSTATUS(status);)
- [exec组函数 对比 system + popen :](#exec组函数 对比 system + popen :)
- 进程间通讯
-
- [pipe 无名管道](#pipe 无名管道)
- [mkfifo 有名管道](#mkfifo 有名管道)
- 消息队列
- 共享内存_映射
- 信号编程
-
- [查看信号: kill -l](#查看信号: kill -l)
- [入门级 接收消息 signal signum](#入门级 接收消息 signal signum)
- [入门级 发送信号 实现杀进程 kill -9 pid](#入门级 发送信号 实现杀进程 kill -9 pid)
- [高级 sigaction 接受信号_携带消息](#高级 sigaction 接受信号_携带消息)
- [高级 sigqueue 发送信号_携带消息](#高级 sigqueue 发送信号_携带消息)
- 信号量编程
- [信号量+共享内存 实现进程通讯](#信号量+共享内存 实现进程通讯)
- 更新日志
文件相关命令
ps -aux|grep init? //搜索包含init名称的进程
top //linux下的资源管理器(动态)
//open 返回的int 是给后面的读/写/光标移动 用的fd,没有open就不能进行后面的操作;
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
close(fd); //关闭文件
// _t 都是返回的int数字;写write,读read,光标移动lseek
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
vimdiff demo1.c demo2.c
//fopen注意mode就行,有:r r+ w w+ a ,返回的文件指针是给后面的读 写 偏移用
FILE *fopen(const char *pathname, const char *mode);
fclose(FILE *); //关闭文件
//跟上面的差不多一样用
//fread/fwrite(读写的数组,读写的大小, 读写的最大次数?, 读写的文件指针)
(读写返回次数的区别:读为有效次数,能一次读完就算你写10次,也返回只读1次)
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
int fseek(FILE *stream, long offset, int whence);
fputc();//写入一个字符;
fgetc();//读取一个字符
feof();/检测是否到达文件末尾,到了返回1;文件结束符为EOF=-1;
//注意:读写操作都会使光标偏移,但也可以利用这点来遍历读写文件;
例:
while(!feof(FILE* fd)){
printf("%c ",fgetc(FILE* fd));
进程相关命令
getpid(); fork(); vfork();
//_t 一律返回的是int
//获取进程ID 就是pid
pid_t getpid(void);
//fork创建子进程
pid_t fork(void);
//这里返回的是的pid = 0 就是子进程,pid > 0 就是父进程;
//所以可以通过判断pid的值,来区别父子进程需要执行的代码;
//注意fork开辟的子进程,没有等待一说,父子进程谁抢到就先运行谁,
//【子进程为僵尸进程】;
//例:
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int num = 0;
pid = getpid();
printf("this pid:%d\n",getpid());
pid_t return_pid = fork();
if(return_pid > 0){
while(1){
printf("this father pid:%d return_pid:%d \n",getpid(),return_pid);
printf("father now num:%d\n",num);
sleep(1);
}
}else if(return_pid == 0){
printf("this son pid:%d return_pid:%d \n",getpid(),return_pid);
num += 2;
printf("child now num:%d\n",num);
exit(6);
}
}
//vfork创建子进程
pid_t vfork(void);
//注意fork开辟的子进程,会等待子进程执行完并exit(num)后,父子进程才继续执行,
//【子进程不会成为僵尸进程】;
//例:
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
pid = getpid();
printf("this pid:%d\n",getpid());
int num = 0;
printf("start_father_num:%d \n",num);
pid_t return_pid = vfork();
if(return_pid > 0){
while(1){
printf("this father pid:%d return_pid:%d \n",getpid(),return_pid);
printf("num = %d\n",num);
sleep(1);
}
}
else if(return_pid == 0){
int i;
for(i=0;i<3;i++){
printf("this son pid:%d return_pid:%d \n",getpid(),return_pid);
num++;
sleep(1);
}
exit(0);
}
return 0;
}
exit(6);wait(status); WEXITSTATUS(status);
//wait() 返回的是子进程的ID 即pid;
//里面的 int *status 是子进程的exit(num)的num码;
//后续使用WEXITSTATUS(status),即可打印出来子进程退出时的状态码;
pid_t wait(int *status);
//例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int status = 0;
pid = getpid();
printf("start father pid:%d\n",getpid());
pid_t return_pid = fork();
if(return_pid > 0 ){
pid_t child_pid = wait(&status);
printf("\n\nwait_return_childe_pid:%d\n",child_pid);
printf("child exit code:%d \n",WEXITSTATUS(status));
while(1){
printf("this father pid:%d fork_return_pid:%d > 0 \n",getpid(),return_pid);
sleep(1);
}
}else if(return_pid == 0){
int i;
for(i=0;i<3;i++){
printf("this son pid:%d fork_return_pid:%d == 0 \n",getpid(),return_pid);
}
exit (6);
}
return 0;
}
exec组函数 对比 system + popen :
精彩博文参照:
https://blog.csdn.net/u014530704/article/details/73848573
观后感:
跟着execl/execlp指定的程序跑了,不回来了!
// date 获取时间的程序
execl("./PATH","date","NULL");
// execl(程序所在路径,程序名,结尾必须为NULL)
// 就像这样用,在当前程序运行到这句代码时,
// 便将替换为后续执行execl所指的程序,不带回头的那种!
execlp("date","date",NULL);
// execlp(程序名,程序名,结尾必须为NULL)
// 就像这样用,它带p,能自己在环境变量下搜索对应的程序并替换后续执行;
// 也是不带回头的那种!
相比较之下 system 执行完指定程序后,还会回来,挺好!
system("cat demo1.c");
//执行完成后返回原程序,继续执行后续代码;
而对比popen 而言,popen除了将指定程序/代码执行完之后,继续执行后续代码外,还将读/写的内容放在管道内,并以文件指针的形式返回;
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("------------------------------------------------\nPS:\n");
char* p = "ps";
FILE *fd = popen(p,"r");
char data[1024];
fread(&data,1024,1,fd);
printf("%s\n",data);
perror("why");
return 0;
}
进程间通讯
精彩博文参照
观后感:
pipe 无名管道
int pipe(int pipefd[2]); (无名管道,在文件里看不到)
里面的fd[2]数组,其中 fd[0] : 读的fd, fd[1] : 写的fd;
//例:通过在父子进程中 close (fd[0]/fd[1]) 配合read(); write(); 实现进程间通讯;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("------------------------------------------------:\n");
int fd[2];
int n_pipe = pipe(fd);
char data1[128];
if(n_pipe < 0){
printf("error: can not creat pipe!\n");
perror("why");
}
int pid = fork();
if(pid < 0){
printf("error: creat child failed!\n");
perror("why");
}
if(pid > 0){
// sleep(2);
printf("this is father pc\n");
close(fd[0]);
write(fd[1],"hello pipe from father;",strlen("hello pipe from father;"));
close(fd[1]);
}
if(pid == 0){
printf("this is child pc\n");
close(fd[1]);
read(fd[0],data1,128);
printf("data : %s\n",data1);
exit(9);
}
return 0;
}
mkfifo 有名管道
//成功返回0;失败返回-1 设置erron = -1;
//返回值判断报错值:EEXIST,可以锁定报错为同名文件已存在目录中;
int mkfifo(const char *pathname, mode_t mode);
RETURN VALUE
On success mkfifo() and mkfifoat() return 0. In the case of
an error, -1 is returned (in which case, errno is set appro‐
priately).
EEXIST pathname already exists. This includes the case where
pathname is a symbolic link, dangling or not.
//例:
#include<stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
if(mkfifo("./demo1.txt",0666) < 0 && errno == EEXIST ){
printf("mkfifo error:\n");
perror("why");
}
return 0;
}
//mkfifo 配合 open read write 完成管道通讯;
//demo mkread:
#include<stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main()
{
char buf[30]={0};
int nff = mkfifo("./demo10.txt",0600);
if(nff < 0 || errno == EEXIST ){
printf("mkfifo error:\n");
perror("why");
}
if(nff == 0){
printf("mkfifo OK! \n");
}
int fd = open("./demo10.txt",O_RDONLY);
printf("open success\n");
int n_read = read(fd,buf,30);
printf("read %d byte frome fifo context:\n%s\n",n_read,buf);
int n_sys = system("rm ./demo10.txt");
if(n_sys < 0 || n_sys ==127 ){
printf("./demo10.txt delect error! \n");
perror("why");
}else{
printf("\n--------------------------------------------");
printf("\nsystem: ./demo10.txt delect success !\n");
printf("--------------------------------------------\n");
}
close(fd);
return 0;
}
//demo mkwrite:
#include<stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main()
{
char buf[30]={"hello mkfifo file_read/write"};
int fd = open("./demo10.txt",O_WRONLY);
printf("open success\n");
int n_write = write(fd,buf,strlen(buf));
printf("write %d byte frome fifo context:\n%s\n",n_write,buf);
close(fd);
return 0;
}
消息队列
// 生成标准key 给后面msgget用;
// key_t ftok(const char *pathname, int proj_id);
// 获取msgid;
// int msgget(key_t key, int msgflg);
// 添加消息
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// 读取消息
// ssize_t msgrcv(int msqid, const void *msgp, size_t msgsz,long msgtyp, int msgflg);
// 控制消息队列 比如:杀掉消息队列
// int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//杀掉消息队列 配合实现: msgctl(n_msgget,IPC_RMID,NULL);
// IPC_RMID
//例a:ftok_msgget_msgsnd_msgctl.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct NB {
long msgtyp;
char data[30];
};
int main()
{
struct NB ZDNB ={998,"Are you ok?"};
printf("%ld\n",ZDNB.msgtyp);
//key_t ftok(const char *pathname, int proj_id);
int key = ftok(".",6);
printf("key = %x\n",key);
//int msgget(key_t key, int msgflg);
int n_get = msgget(key, IPC_CREAT|0777);
if(n_get >= 0){
printf("msgget succes code:%d\n",n_get);
perror("why");
}else{
printf("msgget error! code:%d\n",n_get);
perror("why");
}
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
int snd = msgsnd(n_get,&ZDNB,sizeof(ZDNB.data),0);
printf("msgsnd code:%d\n",snd);
perror("why");
struct NB ZDNB1;
//ssize_t msgrcv(int msqid, const void *msgp, size_t msgsz,long msgtyp, int msgflg);
int rcv = msgrcv(n_get,&ZDNB1,sizeof(ZDNB1.data),888,0);
printf("msgrcv read code:%d\n",rcv);
printf("--------------------------------------------\n");
printf("read frome ./rcv_888 massege is:\n%s\n",ZDNB1.data);
printf("--------------------------------------------\n");
//int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int ctl = msgctl(n_get,IPC_RMID,NULL);
printf("msgctl code:%d\n",ctl);
perror("why");
return 0;
}
//例b:msgrcv.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
struct NB {
long msgtyp;
char data[30];
};
int main()
{
struct NB ZNB1 ={888,"I am ok,Thank you!"};
printf("%ld\n",ZNB1.msgtyp);
struct NB ZNB;
//key_t ftok(const char *pathname, int proj_id);
int key = ftok(".",6);
printf("key = %x\n",key);
//int msgget(key_t key, int msgflg);
printf("key = %x\n",key);
//int msgget(key_t key, int msgflg);
int n_get = msgget(key, IPC_CREAT|0777);
if(n_get >= 0){
printf("msgget succes code:%d\n",n_get);
perror("why");
}else{
printf("msgget error! code:%d\n",n_get);
perror("why");
}
//ssize_t msgrcv(int msqid, const void *msgp, size_t msgsz,long msgtyp, int msgflg);
int rcv = msgrcv(n_get,&ZNB,sizeof(ZNB.data),998,0);
printf("msgrcv read code:%d\n",rcv);
printf("--------------------------------------------\n");
printf("read frome ./snd_998 massege is:\n%s\n",ZNB.data);
printf("--------------------------------------------\n");
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
int snd = msgsnd(n_get,&ZNB1,sizeof(ZNB1.data),0);
printf("msgsnd code:%d\n",snd);
perror("why");
sleep(1);
//int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int ctl = msgctl(n_get,IPC_RMID,NULL);
printf("msgctl code:%d\n",ctl);
perror("why");
return 0;
}
共享内存_映射
// 生成标准key给shmget用;
// key_t ftok(const char *pathname, int proj_id);
// 生成共享内存ID;
// int shmget(key_t key, size_t size, int shmflg);
// 创建映射;通过共享内存ID; shmaddr 写 0;shmflg 写0;--均代表默认方式;
// void *shmat(int shmid, const void *shmaddr, int shmflg);
// int shmdt(const void *shmaddr); (不常用,因为没返回映射指针)
// 关闭映射;
// int shmdt(const void *shmaddr);
// 使用strcpy();写入映射;
// char *strcpy(char *dest, const char *src);
// char *strncpy(char *dest, const char *src, size_t n);
//printf("",);
// 查看当前共享内存映射
// ipcs -m;
// 杀掉共享内存映射ID;
// ipcrm -m shmID;
// 通过内存ID,删除共享文件的内存
// shmctl(shmid,IPC_RMID,0);
//例:shm_strcpy:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>
int main()
{
int key = ftok(".",3);
int shmid = shmget(key,1024*4,IPC_CREAT|0777);
if(shmid < 0){
printf("shmid error ! code:%d\n",shmid);
perror("why");
}
char *shmaddr = shmat(shmid,0,0);
char *cpy = strcpy(shmaddr,"hello shm friends!");
printf("strcpy data to shm:\n%s\n",cpy);
sleep(5);
int dt = shmdt(shmaddr);
if(dt >= 0){
printf("shmdt code:%d\n",dt);
perror("why");
}
shmctl(shmid,IPC_RMID,0);
printf("quite\n");
return 0;
}
//例:shm_printf:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>
int main()
{
int key = ftok(".",3);
int shmid = shmget(key,1024*4,0);
if(shmid < 0){
printf("shmid error ! code:%d\n",shmid);
perror("why");
}
char *shmaddr = shmat(shmid,0,0);
printf("from shm data:\n%s\n",shmaddr);
int dt = shmdt(shmaddr);
if(dt > 0){
printf("shmdt code:%d\n",dt);
perror("why");
}else{
perror("why");
}
shmctl(shmid,IPC_RMID,0);
printf("quite\n");
return 0;
}
信号编程
查看信号: kill -l
入门级 接收消息 signal signum
//sighandler_t signal(int signum, sighandler_t handler);
DESCRIPTION
signal() sets the disposition of the signal
signum to handler,
The signals SIGKILL and SIGSTOP cannot be caught
or ignored.
//例:
#include <stdio.h>
#include <signal.h>
void handler(int signum)
{
printf("signum:%d\n",signum);
switch(signum){
case 2:
printf("SIGINT\n");
break;
case 9:
printf("SIGKILL\n");
break;
}
}
int main()
{
signal(SIGINT,handler);
signal(SIGKILL,handler);
while(1);
return 0;
}
入门级 发送信号 实现杀进程 kill -9 pid
//例:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
int num = atoi(argv[1]);
int pid = atoi(argv[2]);
char buf[30] = {0};
sprintf(buf,"kill %d %d",num,pid);
system(buf);
return 0;
}
高级 sigaction 接受信号_携带消息
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
//void handler(int sig, siginfo_t *info, void *ucontext)
void handler(int signum, siginfo_t *info, void *ucontext)
{
printf("get signum:%d\n",signum);
if(ucontext != NULL){
printf("get data:%d\n",info->si_int);
printf("get data:%d\n",info->si_value.sival_int);
printf("frome pid:%d\n",info->si_pid);
}
}
int main()
{
/*
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *); //if sa_flags = SA_SIGINFO, setthere it is handler;
sigset_t sa_mask;
int sa_flags; //SA_SIGINFO able get sig;
void (*sa_restorer)(void);
};
*/
struct sigaction act;
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = handler;
printf("getpid:%d\n",getpid());
//int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
sigaction(SIGUSR1,&act,NULL);
while(1);
return 0;
}
高级 sigqueue 发送信号_携带消息
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char** argv)
{
//moren have
/*
union sigval {
int sival_int;
void *sival_ptr;
};
*/
int pid = atoi(argv[2]);
int signum = atoi(argv[1]);
union sigval value;
value.sival_int = 666;
printf("getpid:%d\n",getpid());
//int sigqueue(pid_t pid, int signum, const union sigval value);
int que = sigqueue(pid,signum,value);
if(que >= 0){
printf("send int data success!\n");
}else{
perror("why");
}
return 0;
}
信号量编程
信号量(semaphore)与IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
支持信号量组。
//例:通过信号量+/-1,实现父子进程,执行顺序控制;
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
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) */
};
// EXAMPLE
// The following code segment uses semop() to atomically wait for the
// value of semaphore 0 to become zero, and then increment the sema‐
// phore value by one.
// struct sembuf sops[2];
// int semid;
// /* Code to set semid omitted */
// sops[0].sem_num = 0; /* Operate on semaphore 0 */
// sops[0].sem_op = 0; /* Wait for value to equal 0 */
// sops[0].sem_flg = 0;
// sops[1].sem_num = 0; /* Operate on semaphore 0 */
// sops[1].sem_op = 1; /* Increment value by one */
// sops[1].sem_flg = 0;
// if (semop(semid, sops, 2) == -1) {
// perror("semop");
// exit(EXIT_FAILURE);
// }
void pGetKey( int semid) //拿锁/信号量
{
struct sembuf set;
//int semop(int semid, struct sembuf *sops, size_t nsops);
set.sem_num = 0; /* Operate on semaphore 0 */
set.sem_op = -1; //对信号量的值-1,拿掉一个锁;
set.sem_flg = SEM_UNDO; //在进程终止时自动释放所持有的信号量资源
//释放/公布盒子位置;
semop(semid, &set, 1);
printf("get_key sem success!\n");
}
void vPutBackKey( int semid) //还锁/信号量
{
struct sembuf set;
//int semop(int semid, struct sembuf *sops, size_t nsops);
set.sem_num = 0; /* Operate on semaphore 0 */
set.sem_op = 1; //对信号量的值+1,还一个锁;
set.sem_flg = SEM_UNDO; //在进程终止时自动释放所持有的信号量资源
//释放/公布盒子位置;
semop(semid, &set, 1);
printf("back_key sem success!\n\n");
}
int main()
{
int key = ftok(".",2);
//int semget(key_t key,nsems, int semflg);
//获取/创建 1个信号量/1个盒子;
int semid = semget (key,1,IPC_CREAT|0666);
union semun initsem;
initsem.val = 0; //起始信号量的值位0;盒子0个锁;
//int semctl(int semid, int semnum, int cmd, ...);
//如果要SETVAL设置信号量的值,需要多加个联合体变量initsem;
semctl(semid,0,SETVAL,initsem);
int pid = fork();
if(pid > 0){
//去拿锁,但一开始盒子里没有锁,所以就先执行子进程放锁;
pGetKey(semid);
printf("is father pid:%d\n",pid);
//用完了,再把锁放回盒子;
vPutBackKey(semid);
//不需要设值,则3个变量即可,关掉信号量;
semctl(semid,0,IPC_RMID);
}else if(pid == 0){
printf("is child pid:%d\n",pid);
//子进程放锁进去;
vPutBackKey(semid);
}else{
printf("fork error! code:%d\n",pid);
perror("why");
}
return 0;
}
信号量+共享内存 实现进程通讯
//例:(双信号量实现)
//双信号量发送端:
#include <sys/sem.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>
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 semid,int num) //拿锁/信号量
{
struct sembuf set;
//int semop(int semid, struct sembuf *sops, size_t nsops);
set.sem_num = num; /* Operate on semaphore 0 */
set.sem_op = -1; //对信号量的值-1,拿掉一个锁;
set.sem_flg = SEM_UNDO; //在进程终止时自动释放所持有的信号量
资源
//释放/公布盒子位置;
semop(semid, &set, 1);
printf("get_key sem success!\n");
}
void vPutBackKey( int semid,int num) //还锁/信号量
{
struct sembuf set;
//int semop(int semid, struct sembuf *sops, size_t nsops);
set.sem_num = num; /* Operate on semaphore 0 */
set.sem_op = 1; //对信号量的值+1,还一个锁;
set.sem_flg = SEM_UNDO; //在进程终止时自动释放所持有的信号量
资源
//释放/公布盒子位置;
semop(semid, &set, 1);
printf("back_key sem success!\n\n");
}
int main()
{
//shmget use key
int key = ftok(".",3);
int shmid = shmget(key,1024*4,IPC_CREAT|0777);
//semget use key2
int key2 = ftok(".",2);
//int semget(key_t key,nsems, int semflg);
//获取/创建 2个信号量;
//control控制 rd_wr
int semid = semget (key2,2,IPC_CREAT|0666);
//semid是信号集id;
union semun initsem;
union semun initsem2;
initsem.val = 1; //信号量1的值1;1个锁;
initsem2.val = 0;//信号量2的值0;0个锁;
//int semctl(int semid, int semnum, int cmd, ...);
//如果要SETVAL设置信号量的值,需要多加个联合体变量initsem;
//initsem no.0
semctl(semid,0,SETVAL,initsem);
semctl(semid,1,SETVAL,initsem2);
pGetKey(semid,0);
if(shmid < 0){
printf("shmid error ! code:%d\n",shmid);
perror("why");
}
char *shmaddr = shmat(shmid,0,0);
char *cpy = strcpy(shmaddr,"hello _sem_shm friends!");
printf("snd data:\n%s\n",cpy);
int dt = shmdt(shmaddr);
if(dt >= 0){
printf("shmdt code:%d\n",dt);
perror("why");
}
vPutBackKey(semid,1);
shmctl(shmid,IPC_RMID,0);
semctl(semid,0,IPC_RMID);
semctl(semid,1,IPC_RMID);
printf("quite\n");
return 0;
}
//双信号量接收端:
#include <sys/sem.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>
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 semid,int num) //拿锁/信号量
{
struct sembuf set;
//int semop(int semid, struct sembuf *sops, size_t nsops);
set.sem_num = num; /* Operate on semaphore 0 */
set.sem_op = -1; //对信号量的值-1,拿掉一个锁;
set.sem_flg = SEM_UNDO; //在进程终止时自动释放所持有的信号量
资源
//释放/公布盒子位置;
semop(semid, &set, 1);
printf("get_key sem success!\n");
}
void vPutBackKey( int semid,int num) //还锁/信号量
{
struct sembuf set;
//int semop(int semid, struct sembuf *sops, size_t nsops);
set.sem_num = num; /* Operate on semaphore 0 */
set.sem_op = 1; //对信号量的值+1,还一个锁;
set.sem_flg = SEM_UNDO; //在进程终止时自动释放所持有的信号量
资源
//释放/公布盒子位置;
semop(semid, &set, 1);
printf("back_key sem success!\n\n");
}
int main()
{
//shmget use key
int key = ftok(".",3);
int shmid = shmget(key,1024*4,IPC_CREAT|0777);
//semget use key2
int key2 = ftok(".",2);
//int semget(key_t key,nsems, int semflg);
//获取/创建 2个信号量;
//control控制 rd_wr
int semid = semget (key2,2,IPC_CREAT|0666);
//semid是信号集id;
union semun initsem;
union semun initsem2;
initsem.val = 1; //信号量1的值1;1个锁;
initsem2.val = 0;//信号量2的值0;0个锁;
//int semctl(int semid, int semnum, int cmd, ...);
//如果要SETVAL设置信号量的值,需要多加个联合体变量initsem;
//initsem no.0
semctl(semid,0,SETVAL,initsem);
semctl(semid,1,SETVAL,initsem2);
pGetKey(semid,1);
char *shmaddr = shmat(shmid,0,0);
printf("from shm data:\n%s\n",shmaddr);
int dt = shmdt(shmaddr);
if(dt > 0){
printf("shmdt code:%d\n",dt);
perror("why");
}else{
perror("why");
}
vPutBackKey(semid,0);
printf("quite\n");
return 0;
}
//例:(单信号量实现)
//单信号量发送端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#define KEY 1234
// 定义共享内存结构
struct shared_memory {
int data;
};
// 定义信号量操作结构
struct sembuf sem_op;
int main() {
int shm_id, sem_id;
struct shared_memory *shm_ptr;
// 创建共享内存
shm_id = shmget(KEY, sizeof(struct shared_memory), IPC_CREAT | 0666);
if (shm_id == -1) {
perror("shmget");
exit(1);
}
// 连接共享内存
shm_ptr = (struct shared_memory *)shmat(shm_id, NULL, 0);
if (shm_ptr == (struct shared_memory *)(-1)) {
perror("shmat");
exit(1);
}
// 创建信号量
sem_id = semget(KEY, 1, IPC_CREAT | 0666);
if (sem_id == -1) {
perror("semget");
exit(1);
}
// 初始化信号量
semctl(sem_id, 0, SETVAL, 1);
// 写入数据到共享内存
shm_ptr->data = 42;
// 通过信号量控制读进程的访问
sem_op.sem_num = 0;
sem_op.sem_op = 1; // 增加信号量值
sem_op.sem_flg = 0;
semop(sem_id, &sem_op, 1);
// 分离共享内存
shmdt(shm_ptr);
return 0;
}
//单信号量发送端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#define KEY 1234
// 定义共享内存结构
struct shared_memory {
int data;
};
// 定义信号量操作结构
struct sembuf sem_op;
int main() {
int shm_id, sem_id;
struct shared_memory *shm_ptr;
// 创建共享内存
shm_id = shmget(KEY, sizeof(struct shared_memory), IPC_CREAT | 0666);
if (shm_id == -1) {
perror("shmget");
exit(1);
}
// 连接共享内存
shm_ptr = (struct shared_memory *)shmat(shm_id, NULL, 0);
if (shm_ptr == (struct shared_memory *)(-1)) {
perror("shmat");
exit(1);
}
// 创建信号量
sem_id = semget(KEY, 1, IPC_CREAT | 0666);
if (sem_id == -1) {
perror("semget");
exit(1);
}
// 通过信号量等待写进程完成写入
sem_op.sem_num = 0;
sem_op.sem_op = -1; // 减少信号量值
sem_op.sem_flg = 0;
semop(sem_id, &sem_op, 1);
// 读取共享内存中的数据
printf("Data read from shared memory: %d\n", shm_ptr->data);
// 分离共享内存
shmdt(shm_ptr);
// 删除共享内存和信号量
shmctl(shm_id, IPC_RMID, NULL);
semctl(sem_id, 0, IPC_RMID);
return 0;
}
更新日志
23/10/27:
使用markdown编写.md格式,增加目录,
更新内容:
a.信号量;
b.信号量+共享内存实现进程通讯;