【C语言_文件_进程_进程间通讯 常用函数/命令 + 实例】.md_update:23/10/27

news2024/11/17 8:29:06

目录:

    • 文件相关命令
    • 进程相关命令
      • getpid(); fork(); vfork();
      • exit(6);wait(status); WEXITSTATUS(status);
      • exec组函数 对比 system + popen :
        • 精彩博文跳转:
    • 进程间通讯
      • 精彩博文跳转
      • pipe 无名管道
      • mkfifo 有名管道
      • 消息队列
      • 共享内存_映射
      • 信号编程
        • 查看信号: kill -l
        • 入门级 接收消息 signal signum
        • 入门级 发送信号 实现杀进程 kill -9 pid
        • 高级 sigaction 接受信号_携带消息
        • 高级 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;
    }

进程间通讯

精彩博文跳转

http://t.csdnimg.cn/xN2LT

观后感:

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.信号量+共享内存实现进程通讯;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1142588.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

139.【JUC并发编程-04】

JUC-并发编程04 (八)、共享模型之工具1.线程池(1).自定义线程池_任务数小于队列容量(2).自定义线程池_任务数大于队列容量(3).自定义线程池_拒绝策略 2.ThreadPoolExecutor(1).线程池状态(2).构造方法(3).newFixedThreadPool (固定大小线程池)(4).newCachedThreadPool (缓存线程…

企业内部IM即时聊天软件WorkPlus,自主可控的信创即时通讯IM

随着国家的发展发展&#xff0c;很多技术因为一些原因越来越受制于人&#xff0c;尤其是上游核心技术。为了解决这个问题&#xff0c;我国明确了“数字中国”建设战略&#xff0c;强调“自主”、“安全”、“可控”&#xff0c;不被“卡脖子”。在信创产业链的各环节中&#xf…

Linux中shell脚本中的变量

目录 一、变量的定义 二、shell脚本中变量的定义方法 1、变量名称 2、环境级别 3、用户级别 4、系统级别 5、删除设定的变量 三、变量的转译 1、转译 2、声明 3、变量的数组 四、Linux中命令的别名设定 五、用户环境变量的更改 脚本中的传参 1、非交互模式 2…

【VPX611】基于6U VPX总线架构的SATA3.0高性能数据存储板(3.2GByte/s存储带宽)

VPX611是一款基于6U VPX总线架构的高性能数据存储板&#xff0c;该板卡采用2片Xilinx Kintex-7系列FPGA作为主控单元&#xff0c;FPGA内嵌RAID控制器&#xff0c;最大支持8个mSATA盘&#xff0c;最大存储容量可以达到8TByte&#xff0c;持续数据写入带宽可以达到3.2GByte/s。板…

【运维】fstab,systemctl与rc.local启动顺序

前言: 在redis,mongo服务添加systemctl enable启动的情况下&#xff0c;redis和Mongo没有正常启动。排查日志得知,使用到的路径没有挂载。下面截图中的/var/lib/redis和mongo都是软连接&#xff0c;指向了一个服务器的本地盘。 经过排查/var/log/messages以及查阅相关日志得出:…

微积分(三) 不定积分和定积分

前言 微分法也有它的逆运算——积分法。我们已经知道&#xff0c;微分法的基本问题是研究如何从已知函数求出它的导函数&#xff0c;那么与之相反的问题是&#xff1a;求一个未知函数&#xff0c;使其导函数恰好是某一已知函数。 不定积分 假设已知函数A,一个个关于面积的函…

【Linux】NFS服务器搭建配置挂载(Linux挂载Windows目录)

本篇作用于Linux挂载Windows目录&#xff0c;如需要Linux挂载Linux目录请移步我的另一篇文章 http://t.csdnimg.cn/lVrC6http://t.csdnimg.cn/lVrC6 一、Windows端操作步骤 1、创建windows目录&#xff0c;右键目录>属性 2、共享选项>共享按钮>选择Administrator&…

【Python爬虫三天从0到1】Day1:爬虫核心

目录 1.HTTP协议与WEB开发 &#xff08;1&#xff09;简介 &#xff08;2&#xff09;请求协议和响应协议 2. requests&反爬破解 &#xff08;1&#xff09;UA反爬 &#xff08;2&#xff09;referer反爬 &#xff08;3&#xff09;cookie反爬 3.请求参数 &#x…

基于springboot实现校园交友网站管理系统项目【项目源码+论文说明】

基于springboot实现校园交友网站管理系统演示 摘要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生…

为什么说大模型微调是每个人都必备的核心技能?

▼最近直播超级多&#xff0c;预约保你有收获 近期直播&#xff1a;《基于开源 LLM 大模型的微调&#xff08;Fine tuning&#xff09;实战》 0 — 为什么要对 LLM 大模型进行微调&#xff08;Fine tuning&#xff09;&#xff1f; LLM 大模型&#xff08;比如&#xff1a;Chat…

python自动化测试(三):xpath获取元素

目录 前置代码 一、什么是xpath方式 二、通过xpath 单组属性名属性值 的方式进行元素定位 三、通过xpath的多组属性进行元素的定位 四、通过xpath文本值的方式进行元素定位 五、通过模糊的文本值方式进行元素定位 前置代码 # codingutf-8 from selenium import webdrive…

export declare const TestService和export const TestService的区别

两者的主要区别在于导出方式的差异和访问方式的差异。 export declare const TestService&#xff1a;这种方式使用了export declare语法来导出一个常量TestService。export declare语法告诉编译器&#xff0c;此处的声明是供其他模块使用的&#xff0c;但是在当前模块中并没有…

Could not update Flowable database schema: unknown version from database:

文章目录 一、出现问题的情况二、解决方法1、 act_ge_property这个表里面的版本改成flowable-engine的版本号2、act_id_property表的schema.version版本也改成和flowable-engine版本一致&#xff08;如图所示&#xff09; 一、出现问题的情况 项目集成flowable流程框架的时候&…

第15届蓝桥杯Scratch选拔赛中级(STEMA)真题2023年8月

第15届蓝桥杯Scratch选拔赛中级&#xff08;STEMA&#xff09;真题2023年8月 一、单选题 第 1 题 单选题 点击以下积木块&#xff0c;生成的随机数是一个&#xff08; &#xff09;。 A.整数 B.小数 C.整数或小数 D.以上都不对 第 2 题 单选题 运行以下程序&#xff0…

全自动洗衣机什么牌子好?迷你洗衣机品牌推荐

这两年小型洗衣机可以称得上较火的小电器&#xff0c;小小的身躯却有大大的能力&#xff0c;一键可以同时启动洗、漂、脱三种全自动为一体化功能&#xff0c;在多功能和性能的提升上&#xff0c;还可以解放我们双手的同时将衣物给清洗干净&#xff0c;让越来越多小伙伴选择一款…

态势感知中的连续与离散

在态势感知中&#xff0c;连续和离散都是重要的概念。连续通常指的是可以在一定范围内连续变化的状态或变量&#xff0c;例如高度、照度、加速度等。这些连续的状态可以通过传感器等设备进行实时监测和采集&#xff0c;得到连续的数值。在态势感知中&#xff0c;可以利用这些连…

在全新ubuntu上用gpu训练paddleocr模型遇到的坑与解决办法

目录 一. 我的ubuntu版本![在这里插入图片描述](https://img-blog.csdnimg.cn/297945917309494ab03b50764e6fb775.png)二.首先拉取paddleocr源代码三.下载模型四.训练前的准备1.在源代码文件夹里创造一个自己放东西的文件2.准备数据2.1数据标注2.2数据划分 3.改写yml配置文件4.…

规范预算执行,构建企业预算管理一体化建设

随着我国财政改革的不断深入&#xff0c;在财政部总结了历次财政预算改革经验的基础上&#xff0c;我国以优化财政预算管理体系为目标&#xff0c;通过整合各类业务以实现企业预算管理一体化建设。其目的是更好的提升预算管理的质量&#xff0c;系统准确地反映企业预算情况&…

ffmpeg中examples编译报不兼容错误解决办法

ffmpeg中examples编译报不兼容错误解决办法 参考examples下的README可知&#xff0c;编译之前需要设置 PKG_CONFIG_PATH路径。 export PKG_CONFIG_PATH/home/user/work/ffmpeg/ffmpeg/_install_uclibc/lib/pkgconfig之后执行make出现如下错误&#xff1a; 基本都是由于库的版…

如何设置位移贴图模拟物体裂缝?

1、位移贴图的原理&#xff1f; 位移贴图&#xff08;Displacement Map&#xff09;是一种用于增强模型细节的贴图技术&#xff0c;它可以通过改变模型表面的几何形状来实现更加真实的效果。与其他贴图技术不同&#xff0c;位移贴图不仅仅是给模型表面添加纹理和颜色&#xff…