系统编程(4)

作者: 酸菜牛肉 | 来源:发表于2017-01-10 17:08 被阅读24次

    哲学家就餐问题:

    #include<stdio.h>
    #include<pthread.h>
    #include<semaphore.h>
    
    #define N 5
    
    sem_t kuaizis[N];
    sem_t room;
    
    void *phi_thread_func(void *arg);
    
    int main(int argc,char argv[])
    {
        pthread_t thread_ids[N];
        int i = 0;
        sem_init(&room,0,4);
        
        for(i = 0;i < N;i++)
        {
            sem_init(&kuaizis[i], 0, 1);
        }
        for(i = 0;i < N;i++)
        {
            pthread_create(&thread_ids[i],NULL,phi_thread_func,(void *)i);
        }
        for(i = 0;i < N;i++)
        {
            pthread_join(thread_ids[i],NULL);
        }
    
        return 0;
    }
    
    void *phi_thread_func(void *arg)
    {
        int thread_no = (int)arg;
    
        sem_wait(&room);    
        sem_wait(&kuaizis[thread_no]);
        sem_wait(&kuaizis[(thread_no+1)%N]);
        
        printf("pho NO.%d eating...\n",thread_no);
        
        sem_post(&kuaizis[(thread_no+1)%N]);
        sem_post(&kuaizis[thread_no]);
        sem_post(&room);
        
        pthread_exit(NULL);
    }
    

    进程间通信

    无名管道,需要亲子进程来实现

    #include <stdio.h>
    #include <unistd.h>
    
    #define BUFFER_SIZE 1024
    
    // int pipe(int pipefds[2]);
    // 参数:
    //      pipefds 用于接收pipe函数创建的管道文件的读写文件描述符
    //      pipefds[0]      指向管道文件的读端
    //      pipefds[1]      指向管道文件的写端
    // 返回值:成功返回0,失败,返回-1
    
    int main(int argc, char *argv[])
    {
        pid_t child_pid = 0;
        int pipe_fds[2] = {0};
        char buf[BUFFER_SIZE] = {'\0'};
        
        // 创建pipe
        if(pipe(pipe_fds) == -1)
        {
            perror("pipe failed");
            return 1;
        }
        
        // 数据从子进程传递给父进程
        if((child_pid = fork()) == 0)
        {
            int n = 0;
            // child process
            // 1.关闭子进程中管道的读文件描述符
            close(pipe_fds[0]);
            while(1)
            {
                // 2.从标准输入文件中读入数据
                n = read(STDIN_FILENO, buf, BUFFER_SIZE);   
                // 3.将读到的数据写入到管道中
                write(pipe_fds[1], buf, n);
            }
        }
        else if(child_pid > 0)
        {
            int n =0;
            // parent process
            // 1.在父进程中关闭管道的写文件描述符
            close(pipe_fds[1]);
            while(1)
            {
                // 2.从管道中读取数据
                n = read(pipe_fds[0], buf, BUFFER_SIZE);
                // 3.将从管道中读取的数据写入到标准输出文件
                write(STDOUT_FILENO, buf, n);
            }
        }
        else
        {
            // error
        }
    
        return 0;
    }
    

    利用有名管道产生不同窗口的本地聊天

    #include<stdio.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<fcntl.h>
    #include<string.h>
    
    #define USER_NAME_MAX_LEN 100
    #define MSG_MAX_LEN 500
    #define FILE_NAME_MAX_LEN 100
    
    struct msg_node
    {
        char src_username[USER_NAME_MAX_LEN];
        char dst_username[USER_NAME_MAX_LEN];
        char text[MSG_MAX_LEN];
    };
    
    int main(int argc,char *argv[])
    {
        if(argc != 2)
        {
            printf("usage:%s<username>\n",argv[0]);
            return -1;
        }
        
        char filename[FILE_NAME_MAX_LEN] = {'\0'};
        pid_t child_pid;
    
        
        sprintf(filename,"%s.fifo",argv[1]);
        if(access(filename,F_OK) != 0)
        {
            mkfifo(filename,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
        }
        
        if((child_pid = fork()) == 0)
        {
            int n = 0;
            struct msg_node msg;
            int fd = 0;
            while(1)
            {
                if((fd = open(filename,O_RDONLY)) == -1)
                {
                    perror("open failed");
                    return -1;
                }   
                while((n = read(fd,&msg,sizeof(msg))) > 0)
                {
                    printf("%s ----> %s : %s\n",msg.src_username,msg.dst_username,msg.text);
                }
            
                close(fd);
            }
        }
        
        else if(child_pid > 0)
        {
            //char buf[MSG_MAX_LEN] = {'\0'};
            struct msg_node msg;
            int fd = 0;
            char dst_filename[FILE_NAME_MAX_LEN] = {'\0'};
            
            strcpy(msg.src_username,argv[1]);
            
            while(1)
            {
                printf("to>");
                fgets(&msg.dst_username,USER_NAME_MAX_LEN,stdin);
                msg.dst_username[strlen(msg.dst_username)-1] = '\0';
                
                printf("text>");
                fgets(&msg.text,MSG_MAX_LEN,stdin);
                msg.text[strlen(msg.text)-1] = '\0';
                
                sprintf(dst_filename,"%s.fifo",msg.dst_username);
                
                //printf("%s\n",dst_filename);
                
                if((fd = open(dst_filename,O_WRONLY)) == -1)
                {
                    perror("open failed");
                    continue;
                }
                //printf("*****\n");
                write(fd,&msg,sizeof(msg));
                
                close(fd);
            }
        }
        else
        {
        
        }
        
        remove(filename);
        return 0;
    }
    

    共享内存间通信,使用信号量,效率最高
    两个进程实现教师信息的传递

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define ARR_MAX_LEN 100
    
    int main(int argc, char *argv[])
    {
        int shmid = 0;
        struct teacher_node
        {
            int tea_id;
            char tea_name[ARR_MAX_LEN];
            int tea_age;
            char tea_favite[ARR_MAX_LEN];
        };
        key_t key;
        struct teacher_node teacher;
        memset(&teacher, 0, sizeof(teacher));
        
        key = ftok("/", 'j');
        if((shmid = shmget(key, sizeof(teacher), IPC_CREAT | S_IRUSR | S_IWUSR)) == -1)
        {
            perror("shmget failed");
            return -1;
        }
       // printf("shmid = %d\n",shmid);
        
        teacher.tea_id = 123;
        strcpy(teacher.tea_name,"xiaowang");
        teacher.tea_age = 23;
        strcpy(teacher.tea_favite,"basketball");
        
        struct teacher *p = shmat(shmid, NULL, 0);
        //getchar();
       // printf("input teacher msg:id,name,age,favite\n");
    
            // 2.3将输入的教师信息拷贝
        memcpy(p, &teacher, sizeof(teacher));
    
        shmdt(&teacher);
    
        return 0;
    }
    
    

    进程间同步同步共享资源

    // 本文件是对信号量集中只有一个信号量的操作的封装
    
    #ifndef __SQ_SEM_H__
    #define __SQ_SEM_H__
    
    #include <sys/types.h>
    
    // semctl函数的第四个参数类型
    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) */
    };
    
    // 创建/获取信号量集
    int sq_sem_get(key_t key, int semflg);
    
    // 初始化信号量集
    int sq_sem_init(int semid, int value);
    
    // 对信号量集进行wait操作(-1)
    int sq_sem_wait(int semid);
    
    // 对信号量集进行post操作(+1)
    int sq_sem_post(int semid);
    
    // 销毁信号量集
    int sq_sem_destroy(int semid);
    #endif
    _____
    
    #include "sq_sem.h"
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    
    // 创建/获取信号量集
    int sq_sem_get(key_t key, int semflg)
    {
        return semget(key, 1, semflg);
    }
    
    // 初始化信号量集
    int sq_sem_init(int semid, int value)
    {
        union semun arg;
        arg.val = value;
        
        return semctl(semid, 0, SETVAL, arg);
    }
    
    // 对信号量集进行wait操作(-1)
    int sq_sem_wait(int semid)
    {
        struct sembuf s_op;
        s_op.sem_num = 0;
        s_op.sem_op = -1;
        s_op.sem_flg = SEM_UNDO;
        
        return semop(semid, &s_op, 1);
    }
    
    // 对信号量集进行post操作(+1)
    int sq_sem_post(int semid)
    {
        struct sembuf s_op;
        s_op.sem_num = 0;
        s_op.sem_op = 1;
        s_op.sem_flg = SEM_UNDO;
        
        return semop(semid, &s_op, 1);
    }
    
    
    // 销毁信号量集
    int sq_sem_destroy(int semid)
    {
        return semctl(semid, 0, IPC_RMID);
    }
    
    _____
    
    // 模拟在父进程和子进程之前以共享内存的方式交换数据
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include "sq_sem.h"
    
    struct teacher
    {
        int no;
        char name[50];
    };
    
    int main(int argc, char *argv[])
    {
        pid_t child_pid = 0;
        int sem_id = 0;
        int shm_id = 0;
        key_t key;
        
        // 生成唯一key值用于获取信号量集和共享内存
        key = ftok("/", 'a');
        // 1.1获取共享内存
        if((shm_id = shmget(key, sizeof(struct teacher), IPC_CREAT | 0600)) == -1)
        {
            perror("shmget failed");
            return 1;
        }
        // 1.2获取信号量集用于同步使用共享内存
        if((sem_id = sq_sem_get(key, IPC_CREAT | 0666)) == -1)
        {
            perror("sq_sem_get failed");
            return 2;
        }
        // 1.3初始化信号量集
        sq_sem_init(sem_id, 0);
        
        if((child_pid = fork()) == 0)   // 子进程
        {
            // 用于存储从共享内存中获取的数据
            struct teacher teach;
            memset(&teach, 0, sizeof(teach));
            
            // 子进程负责从共享内存中读入数据
            // 2.1绑定共享内存
            struct teacher *p = (struct teacher *)shmat(shm_id, NULL, 0);
            
            // 2.2先wait信号量,确保共享内存中有数据可读
            sq_sem_wait(sem_id);
            
            // 2.3从共享内存中读出数据
            memcpy(&teach, p, sizeof(teach));
            
            // 2.4打印读出的数据
            printf("techer : no = %d, name = %s\n",
                teach.no, teach.name);
                
            // 3.解除共享内存的绑定
            shmdt(p);
                  
            // 子进程退出    
            exit(0);
        }
        else if(child_pid > 0)          // 父进程
        {
            // 用于存储从键盘读入的教师信息
            struct teacher teach;
            memset(&teach, 0, sizeof(teach));
            
            // 父进程负责从键盘读入教师信息,写入共享内存
            // 2.1从键盘读入教师信息
            printf("input no>");
            scanf("%d", &teach.no);
            printf("input name>");
            scanf("%s", teach.name);
            
            // 2.2绑定共享内存
            struct teacher *p = (struct teacher *)shmat(shm_id, NULL, 0);
            
            // 2.3将输入的教师信息拷贝
            memcpy(p, &teach, sizeof(teach));
            
            // 2.4对信号量集进行post操作
            sq_sem_post(sem_id);
            
            // 3.解除共享内存的绑定
            shmdt(p);
            
            // 防止僵尸进程    
            wait(NULL);  
            
            // 父进程退出
            exit(0);
        }
        else
        {
        }
    
        return 0;
    }
    
    
    

    相关文章

      网友评论

      • introduction:请问一下semget函数在哪里。。
        酸菜牛肉: @introduction 那个应该是系统内置的函数,你查一下man手册,里边应该有

      本文标题:系统编程(4)

      本文链接:https://www.haomeiwen.com/subject/nbicbttx.html