進程間通信

進程的讀寫

寫文件的進程只能單個運行(寫的時候禁止讀),讀文件的進程可以同時有多個,
讀寫的互斥鎖wsem,rsem
讀寫進程的優先性同級,讀進程有優先權時(讀的時候拿走寫鎖),

進程間通信方式

Pipe, fifo, shared memory, mmap, samaphone, socket, mesgq,
有名管道和無名管道
共享文件
共享內存
消息隊列
內存映射
socket監聽套接字
信號量

管道

管道通信詳解
管道為單向, Pipe,上級進程創建,無名管道通信
pipe, pipe2 - create pipe

   #include <unistd.h>
   int pipe(int pipefd[2]);
   #define _GNU_SOURCE             /* See feature_test_macros(7) */
   #include <fcntl.h>              /* Obtain O_* constant definitions */
   #include <unistd.h>
   int pipe2(int pipefd[2], int flags);
  return -1 為失敗

管道通信函數例

// ./named-pipe-chat  發送消息
#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;
    }

    // 子進程ID
    pid_t child_pid;
    // 登陸用戶的命令管道文件名
    char filename[FILE_NAME_MAX_LEN] = {'\0'};

    // 構造登陸用命名的管道文件名,并判定用戶是否存在
    sprintf(filename, "%s.fifo", argv[1]);
    if(access(filename, F_OK) != 0)//判斷用戶名文件是否存在,存在返回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;
        
        // 1.打開登陸用戶的管道文件,用于接收其他用戶發送的消息數據結構體
        if((fd = open(filename, O_RDONLY)) == -1)
        {
            perror("open failed");
            return 1;
        }
        // 2.循環的從管道文件中讀入消息信息,并打印顯示
        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)          // 父進程,負責從鍵盤讀入相關數據,寫入執行用戶的管道文件
    {
        struct msg_node msg ;
        int fd = 0;
        // 接收用戶的管道文件名
        char dst_filename[FILE_NAME_MAX_LEN] = {'\0'};
                   
        // 發送者永遠為當前登錄用戶
        strcpy(msg.src_username, argv[1]);
        
            // 1.輸入接收消息的用戶名名稱
            printf("to>");
            fgets(&msg.dst_username, USER_NAME_MAX_LEN, stdin);
            // 1.1將用戶名末尾的'\n'替換為'\0'
            msg.dst_username[strlen(msg.dst_username)-1] = '\0';
            // 1.2構造接收用戶的管道文件名
            sprintf(dst_filename, "%s.fifo", msg.dst_username) ;
            // 1.3打開管道文件
            if((fd = open(dst_filename, O_WRONLY)) == -1)
            {
                perror("open failed");
                return 1;
            } 
      // 循環的發送從鍵盤讀入的數據
        while(1)
        {
            // 2.輸入待發送的消息字符串
            printf("text>");
            fgets(&msg.text, MSG_MAX_LEN, stdin);
            // 2.2將消息文本末尾的'\n'替換為'\0'
            msg.text[strlen(msg.text)-1] = '\0';
            
            // 3.將構造的消息結構體寫入管道文件
                
                
            // 3.2將構造的結構體寫入管道文件
            write(fd, &msg, sizeof(msg));
            // 3.3close
        }
       close(fd);
    }
    else
    {
    }
    
    // 刪除登陸用戶的管道文件
    remove(filename);

    return 0;
}

有名管道通信

mkfifo
mkfifo - make a FIFO special file (a named pipe)
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
return 成功返回0,失敗返回1

有名管道--寫信息
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int n = 0;
    char buf[1024] = {'\0'};
    int fd = 0;

    // 判斷有名管道文件是否存在,不存在則創建
    if(access("test_file.fifo", F_OK) != 0 )
    {
        mkfifo("test_file.fifo", 
            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    }
    // 1.打開管道文件
    if((fd = open("test_file.fifo", O_WRONLY)) == -1)
    {
        perror("open failed");
        return 1;
    }

    printf("waiting for input data...\n");
    while(1)
    {
        // 2.從標準輸入文件中讀入數據
        n = read(STDIN_FILENO, buf, 1024);
        // 3.將讀到的數據寫入到管道文件中
        write(fd, buf, n);
    }
    
    printf("writer process exit...\n");
    
    return 0;
}
有名管道--讀取信息
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>

int main(int argc, char *argv[])
{
    int n = 0;
    char buf[1024] = {'\0'};
    int fd = 0;
    
       
    // 1.打開管道文件
    fd = open("test_file.fifo", O_RDONLY);
    if(fd == -1)
    {
        perror("open failed");
        return 1;
    }
    
    printf("reading for writer data...\n");
    // 2.從管道文件中讀取數據
    while((n = read(fd, buf, 1024)) > 0)
    {
        // 3.將讀到的數據寫入到標準輸出文件中
        write(STDOUT_FILENO, buf, n);
    }
    
    printf("reader process exit...\n");
    
    return 0;
} 
互斥鎖,線程間通信的函數例
#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 i =0;
    pthread_t thread_ids[N];
    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("%d eating\n",thread_no);

sem_post(&kuaizis[(thread_no+1)%N]);
sem_post(&kuaizis[thread_no]);
sem_post(&room);

pthread_exit(NULL);
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容