三、初始化共享内存

vim selec.c

开始播放涉及到多进程并发涉及到共享内存

当输出1的时候开始播放音乐

case 1:
    start_play()
    break;

在main.c中初始化共享内存

    //初始化共享内存
    ret = InitShm();
    if (FAILURE == ret)
    {
        printf("共享内存初始化失败\n");
        exit(1);
    }

player.h

#ifndef PLAYER_H
#define PLAYER_H

#include <unistd.h>

#define MUSICPATH   "/root/music_list/"

#define SHMKEY     1234
#define SHMSIZE    4096

#define SEQUENCEMODE    1
#define RANDOM          2
#define CIRCLE          3

//共享内存数据
struct shm
{
    int play_mode;
    char cur_name[64];
    pid_t ppid;
    pid_t child_pid;
    pid_t grand_pid;
};
typedef struct shm shm;

int InitShm();
#endif

vim play.c

void *g_addr = NULL;      //共享内存映射地址


int g_start_flag = 0;     //表示没有开始播放音乐
int g_suspend_flag = 0;   //表示没有暂停

int InitShm()
{
    //创建共享内存
    shmid = shmget(SHMKEY, SHMSIZE, IPC_CREAT | IPC_EXCL);
    if (-1 == shmid)
    {
        return FAILURE;
    }

    //映射
    g_addr = shmat(shmid, NULL, 0);
    if (NULL == g_addr)
    {
        return FAILURE;
    }

    //初始化共享内存数据
    shm s;
    s.play_mode = SEQUENCEMODE;
    s.ppid = getpid();   //父进程pid存入
    memcpy(g_addr, &s, sizeof(s)); //把初始数据写入共享内存,播放模式和父进程id

    return SUCCESS;
}

在pleyer.c中编写开始播放的主要程序

void start_play()
{
    if (g_start_flag == 1)     //已经开始播放
    {
        return;
    }

    //获取歌曲名称
    if (head->next == NULL)    //空链表
    {
        return;
    }


    开始播放音乐
    play_music(head->next->music_name);

    
    g_start_flag = 1;
}

开始播放需要有三个进程的

父进程创建子进程,子进程创建孙进程

父进程作用产生子进程,孙进程播放音乐

void play_music(const char *name)
{
    pid_t child_pid = fork();  // 创建子进程
    if (-1 == child_pid)         //创建失败
    {
        perror("fork");
        exit(1);
    }
    else if (0 == child_pid)         //子进程
    {
        while (1)  //子进程死循环
        {
            pid_t grand_pid = vfork(); //创建孙进程
            if (-1 == grand_pid)
            {
                perror("fork");
                exit(1);
            }
            else if (0 == grand_pid)    //孙进程
            {   
                 shm s ;
               char cur_name[64] = {0};

                //获取共享内存
                int shmid = shmget(SHMKEY, SHMSIZE, 0);
                if (-1 == shmid)
                {
                    perror("shmget");
                    exit(1);
                }

                //映射
                void *addr = shmat(shmid, NULL, 0);
                if (NULL == addr)
                {
                    perror("shmat");
                    exit(1);
                }
                if (strlen(name) != 0)      //直接开始播放
                {
                    strcpy(cur_name, name);   

                }
                else                        //遍历链表,找到一首歌播放
                {
                    //判断播放模式,找到一首歌曲
                    memcpy(&s, addr, sizeof(s));
                    FindNextMusic(s.cur_name, s.play_mode, cur_name);
                }
                //把信息写入共享内存(父子孙进程号、当前歌曲名)
                shm s;
                strcpy(s.cur_name, name);
                
               
                s.child_pid = getppid();
                s.grand_pid = getpid();
                memcpy(addr, &s, sizeof(s));
                shmdt(addr);           //解除映射
                    char music_path[128] = {0};
                    strcpy(music_path, MUSICPATH);
                    strcat(music_path, cur_name);
                    execl("/bin/madplay", "madplay", music_path, NULL); 

                

                



            }
            else                        //子进程
            {
                memset((void *)name, 0, strlen(name));         //歌曲名长度变为0,方便下一次操作

                int status;
                waitpid(grand_pid, &status, 0);        //回收孙进程
            }
        }
    }
    else
    {
        return;
    }
}

因为涉及到上一首下一首,需要改变链表,上一首下一首,双向循环链表

link.h

#ifndef LINK_H
#define LINK_H

struct Node
{
    char music_name[64];
    struct Node *next;
    struct Node *prior;
};
typedef struct Node Node;

int InitLink();
#endif

link.c

//初始化双向循环链表
int InitLink()
{
    head = (Node *)malloc(sizeof(Node) * 1);
    if (NULL == head)
    {
        return FAILURE;
    }

    head->next = head;
    head->prior = head;

    return SUCCESS;
}
int InsertLink(Node *h, const char *name)
{
    if (NULL == h || NULL == name)
    {
        return FAILURE;
    }

    Node *end = h->prior;


    Node *n = (Node *)malloc(sizeof(Node) * 1);
    if (NULL == n)
    {
        return FAILURE;
    }

    n->next = h;
    strcpy(n->music_name, name);
    end->next = n;
    n->prior = end;
    h->prior = n;

    return SUCCESS;
}
/*
函数描述:根据当前歌曲和播放模式,找到下一首歌
函数参数:cur:当前歌曲
          mode:播放模式
          next:存放下一首歌名
返回值:无
*/
void FindNextMusic(const char *cur, int mode, char *next)
{
    if (mode == CIRCLE)     //单曲循环,把当前音乐再赋值给下一首歌
    {
        strcpy(next, cur);
        return;
    }
    else if (mode == SEQUENCEMODE)//循环播放
    {
        Node *p = head->next;//创建新节点指向头结点的下一个节点
        while (strcmp(p->music_name, cur) != 0) //找到当前播放音乐
        {
            p = p->next;
        }
            
        if (p->next == head)          //忽略头结点,指向头结点的下一个
        {
            strcpy(next, head->next->music_name);
        }
        else
        {
            strcpy(next, p->next->music_name);//将找到的下一首音乐的名字赋值给next
        }
        return;
    }
    else //上述模式都不是则是四级播放
    {
        Node *p = head->next;
        srand(time(NULL)); //随机查找种子
        int num = rand() % 100;

        int i;
        for (i = 0; i < num; i++)
        {
            p = p->next;
        }

        if (p == head)
        {
            strcpy(next, head->next->music_name);
        }
        else
        {
            strcpy(next, p->music_name);
        }

        return;
    }
}

link.h

#ifndef LINK_H
#define LINK_H

struct Node
{
    char music_name[64];
    struct Node *next;
    struct Node *prior;
};
typedef struct Node Node;

int InitLink();
void FindNextMusic(const char *cur, int mode, char *next);
int InsertLink(Node *h, const char *name);
#endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值