信号灯集和共享内存的综合应用小例子
  8caZn4LUURFU 2023年11月19日 23 0


要求:使用信号灯集和共享内存实现:一个进程对共享内存存放数据"Nice to meet you"循环倒置,一个进程循环输出共享内存的内容,要确保倒置一次打印一次。

分析:这两个进程可以写成两个源文件,一个文件对应一个进程,从题目要求可以看出,这两个进程实现的是一种进程间的同步关系,即想要进程打印信息必须要另一进程完成数组内容的倒置,然后该进程倒置完成一次之后不能就马上再倒置,要打印进程完成对上次倒置内容的打印才可以。用PV操作来展示他们之间的关系如下:

信号灯集和共享内存的综合应用小例子_c语言

//reverse.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

union semun {
    int val;
};
void sem_init(int semid, int num, int val) //信号灯集初始化函数
{
    union semun sem;
    sem.val = val;
    semctl(semid, num, SETVAL, sem);
}
void sem_op(int semid, int num, int op) //pv操作函数
{
    struct sembuf buf;
    buf.sem_num = num;
    buf.sem_op = op;
    buf.sem_flg = 0;
    semop(semid, &buf, 1);
}
char reverse(char *head, char *tail)
{
    while (head < tail)
    {
        *head ^= *tail;
        *tail ^= *head;
        *head++ ^= *tail--;
    }
}
int main(int argc, char const *argv[])
{
    char s[32] = {0};
    //创建key值
    key_t key = ftok(".", 'a');
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    //shmget
    int shmid = shmget(key, 32, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid <= 0)
    {
        if (errno = EEXIST)
            shmid = shmget(key, 32, 0666);
        else
        {
            perror("shmget err");
            return -1;
        }
    }
    //shmat
    char *p = (char *)shmat(shmid, NULL, 0);
    if (p == (char *)-1)
    {
        perror("shmat err");
        return -1;
    }
    //semget
    int semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0666);
    if (semid <= 0)
    {
        if (errno = EEXIST)
            semid = semget(key, 1, 0666);
        else
        {
            perror("semget err");
            return -1;
        }
    }
    else
    {
        sem_init(semid, 0, 1); //初始化信号灯集0
        sem_init(semid, 1, 0); //初始化信号灯集1
    }
    fputs("请输入字符串:", stdout);
    fgets(p, 32, stdin);
    if (p[strlen(p) - 1] == '\n')
        p[strlen(p) - 1] = '\0';
    char *head = NULL;
    char *tail = NULL;
    while (1)
    {
        head = p;
        tail = p + strlen(p) - 1;
        sem_op(semid, 0, -1);
        reverse(p, p + strlen(p) - 1); //倒置
        printf("倒置...%p\n",p);
        sem_op(semid, 1, 1);
    }
    shmdt(p);
    shmctl(shmid, IPC_RMID, NULL);
    //删除信号灯集
    semctl(semid, 0, IPC_RMID);
    return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>


union semun {
    int val;
};
void sem_init(int semid, int num, int val) //信号灯集初始化函数
{
    union semun sem;
    sem.val = val;
    semctl(semid, num, SETVAL, sem);
}
void sem_op(int semid, int num, int op) //pv操作函数
{
    struct sembuf buf;
    buf.sem_num = num;
    buf.sem_op = op;
    buf.sem_flg = 0;
    semop(semid, &buf, 1);
}

int main(int argc, char const *argv[])
{
    // char s[32] = {0};
    //创建key值
    key_t key = ftok(".", 'a');
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    //shmget
    int shmid = shmget(key, 32, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid <= 0)
    {
        if (errno = EEXIST)
            shmid = shmget(key, 32, 0666);
        else
        {
            perror("shmget err");
            return -1;
        }
    }
    //shmat
    char *p = (char *)shmat(shmid, NULL, 0);
    if (p == (char *)-1)
    {
        perror("shmat err");
        return -1;
    }
    //semget
    int semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0666);
    if (semid <= 0)
    {
        if (errno = EEXIST)
            semid = semget(key, 1, 0666);
        else
        {
            perror("semget err");
            return -1;
        }
    }
    else
    {
        sem_init(semid, 0, 1); //初始化信号灯集0
        sem_init(semid, 1, 0); //初始化信号灯集1
    }
    while (1)
    {
        sem_op(semid, 1, -1);
        printf("%s\n",p); //dayin
        sleep(1);
        sem_op(semid, 0, 1);
    }

    shmdt(p);
    shmctl(shmid, IPC_RMID, NULL);
    //删除信号灯集
    semctl(semid, 0, IPC_RMID);
    return 0;
}
  • 上面程序中对信号灯的初始化和PV操作进行了函数的封装,使得代码更具模块化,不显得太乱,同时功能实现起来更为方便。
  • 两个数据交换使用了 ^= 的方式,这可以不设置第三个变量,数据交换完全是在原地址空间实现的


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月19日 0

暂无评论

推荐阅读
8caZn4LUURFU