linux信号量与进程通信

1.线程任务同步:
    1.信号量:
        是一种资源,可以被申请、释放、初始化
        释放:让资源数+1,不会阻塞
        申请:让资源数-1,如果当前资源数为0,申请资源时会阻塞等待,直到资源不为0,才能继续向下执行

        Linux内核:
            PV操作, P申请 V释放

    2.函数接口:
        1.sem_init
          int sem_init(sem_t *sem, int pshared, unsigned int value);
          功能:
            信号量的初始化
          参数:
            sem:信号量空间首地址
            pshared:
                0   线程间使用
                非0 进程间使用
            value:
                信号量初始化的值
          返回值:
            成功返回0 
            失败返回-1 
        
        2.sem_destroy 
          int sem_destroy(sem_t *sem);
          功能:
            信号量的销毁 

        3.sem_wait 
          int sem_wait(sem_t *sem);
          功能:
            信号量资源申请

        4.sem_post 
          int sem_post(sem_t *sem);
          功能:
            信号量资源释放

练习:
    创建3个线程任务,任务一循环打印 "A",任务二循环打印"B",
    任务三循环打印"C",要求打印出来的顺序总是先
    "A" -> "B" -> "C"

#include 
#include 
#include 
#include 

sem_t sem_a;
sem_t sem_b;
sem_t sem_c;

void *WriteA(void *arg)
{
    while(1)
    {
        sem_wait(&sem_a);
        sleep(3);
        printf("A\n");
        sem_post(&sem_b);
    }
    return NULL;
}

void *WriteB(void *arg)
{
    while(1)
    {
        sem_wait(&sem_b);
        sleep(3);
        printf("B\n");
        sem_post(&sem_c);
    }
    return NULL;
}

void *WriteC(void *arg)
{
    while(1)
    {
        sem_wait(&sem_c);   
        sleep(3);
        printf("C\n");
        sem_post(&sem_a);
    }
    return NULL;
}

int main(void)
{
    pthread_t tid1;
    pthread_t tid2;
    pthread_t tid3;

    sem_init(&sem_a, 0, 1);
    sem_init(&sem_b, 0, 0);
    sem_init(&sem_c, 0, 0);

    pthread_create(&tid1, NULL, WriteA, NULL);
    pthread_create(&tid2, NULL, WriteB, NULL);
    pthread_create(&tid3, NULL, WriteC, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_join(tid3, NULL);

    sem_destroy(&sem_a);
    sem_destroy(&sem_b);
    sem_destroy(&sem_c);

    return 0;
}

2.进程间通信的方式:
    1.管道
    2.信号
    3.消息队列
    4.共享内存
    5.有名信号量
    6.本地域套接字

3.管道:
    1.无名管道
        只能用于具有亲缘关系的进程间通信

        1.pipe
          int pipe(int pipefd[2]);
          功能:
            创建一个无名管道,获得操作管道的两个文件描述符
            pipefd[0]:读管道文件描述符
            pipefd[1]:写管道文件描述符
          返回值:
            成功返回0 
            失败返回-1 
        
        无名管道就是一段内核缓存区

        2.无名管道特点:
            1.如果有写端:
                1.如果有数据,直接读取数据
                2.如果没有数据,阻塞等待直到读取到数据,再继续向下执行
            2.如果没有写端:
                1.如果有数据,直接读取数据
                2.如果没有数据,不阻塞等待直接向下执行
            3.如果有读端:
                1.如果管道中没有写满(64k),则直接写入
                2.如果管道中写满(64k),阻塞等待,直到有数据读出才能继续写入
            4.如果没有读端:
                1.向管道中写入数据会产生管道破裂,导致进程异常退出

    2.有名管道
        1.mkfifo
          int mkfifo(const char *pathname, mode_t mode);
          功能:
            创建有名管道
          参数:
            pathname:有名管道路径
            mode:权限
          返回值:
            成功返回0 
            失败返回-1 

        2.有名管道:
            1.必须读写两端同时加入,才能继续向下执行

练习:
    1.编程程序实现两个进程交替收发数据:
        write.c                read.c 
        从终端接收数据  
        发送给read.c
                               接收write.c内容 
                               从终端接收数据
                               发送给write.c 

        hello world             
                                thank you
        aXX 
                                XXX

ATOB.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int fdwrite;
int fdread;
int isRun = 1;

void *ChatWrite(void *arg)
{
    fdwrite = open("./tmpBTOA", O_WRONLY);
    while(isRun)
    {
        char tmpbuffer1[4096] = {0};
        fgets(tmpbuffer1, sizeof(tmpbuffer1), stdin);
        char *find = strchr(tmpbuffer1, '\n');
        if(find)
        {
            *find = '\0';
        }
        if(0 == strcmp(tmpbuffer1, "quit"))
        {
            isRun = 0;
        }
        write(fdwrite, tmpbuffer1, strlen(tmpbuffer1));
    }

    return NULL;
}

void *ChatRead(void *arg)
{
    fdread = open("./tmpATOB", O_RDONLY);
    while(isRun)
    {
        char tmpbuffer2[4096] = {0};
        read(fdread, tmpbuffer2, sizeof(tmpbuffer2));
        if(0 == strcmp(tmpbuffer2, "quit"))
        {
            isRun = 0;
        }
        printf("RECV:%s\n", tmpbuffer2);
    }

    return NULL;
}

BTOA.c
int main(void)
{
    pthread_t pid1;
    pthread_t pid2;

    mkfifo("./tmpBTOA", 0664);
    
    pthread_create(&pid1, NULL, ChatWrite,NULL);
    pthread_create(&pid2, NULL, ChatRead, NULL);

    pthread_join(pid1, NULL);
    pthread_join(pid2, NULL);
    close(fdwrite);
    close(fdread);

    return 0;
}

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int fdwrite;
int fdread;
int isRun = 1;

void *ChatWrite(void *arg)
{
    fdwrite = open("./tmpATOB", O_WRONLY);
    while(isRun)
    {
        char tmpbuffer1[4096] = {0};
        fgets(tmpbuffer1, sizeof(tmpbuffer1), stdin);
        char *find = strchr(tmpbuffer1, '\n');
        if(find)
        {
            *find = '\0';
        }
        if(0 == strcmp(tmpbuffer1, "quit"))
        {
            isRun = 0;
        }
        write(fdwrite, tmpbuffer1, strlen(tmpbuffer1));
    }

    return NULL;
}

void *ChatRead(void *arg)
{
    fdread = open("./tmpBTOA", O_RDONLY);
    while(isRun)
    {
        char tmpbuffer2[4096] = {0};
        read(fdread, tmpbuffer2, sizeof(tmpbuffer2));
        if(0 == strcmp(tmpbuffer2, "quit"))
        {
            isRun = 0;
        }
        printf("RECV:%s\n", tmpbuffer2);
    }

    return NULL;
}

int main(void)
{
    pthread_t pid1;
    pthread_t pid2;
    
    mkfifo("./tmpATOB", 0664);

    pthread_create(&pid1, NULL, ChatWrite, NULL);
    pthread_create(&pid1, NULL, ChatRead, NULL);
    
    pthread_join(pid1, NULL);
    pthread_join(pid2, NULL);
    close(fdwrite);
    close(fdread);

    return 0;
}

你可能感兴趣的:(linux,运维,服务器)