【pthread库使用之封装信号量+共享内存】

信号量+共享内存通信

该文章主要用c语言实现共享内存方式的进程间通信,通信过程使用有名信号量控制对应进程的读写,进而判断该进程是否可读,可写。
该实现方式申请了两块共享内存,创建了两对信号量(一对信号量用来控制一个进程的读写,即创建了4个信号量,4个信号量控制分别控制读写,方便理解),使得两个进程可以同时读写。

代码不是全部代码,需自行理解并适配自己的代码逻辑


信号量初始化

#define Printf(format, ...) \
do\
{\
    printf("%s(%d):", __func__, __LINE__); \
    printf(format, ##__VA_ARGS__);         \
    printf("\n");         \
}\
while(0)

/**************************************************************************
    函数名称: Set_SemTimeOut
    功能描述: 设置信号量等待超时时间 
    输入参数: IN int Mode                               判断模式;0-不分白天夜晚、1-白天、2-夜晚
              IN double current_time                时间
              IN JSON_DATA *pstJsonData             config文件中的json数据
    输出参数: 
    注 意 点: 该函数固定设置超时时间为120s
***************************************************************************/
int Set_SemTimeOut(OUT struct timespec *pstTime)
{
    struct timespec stTime;
    
    memset(&stTime, 0, sizeof(stTime));
    
    if (NULL == pstTime)
    {
        log_e("[CURL]Invalid parameter");
        return ERR_COMMON_INVALID_PARAM;
    }
    
    stTime.tv_sec = time(NULL) + 120;
    stTime.tv_nsec = 0;
    
    memcpy(pstTime, &stTime, sizeof(stTime));

    return ERR_COMMON_SUCCEED;
}

/**************************************************************************
    函数名称: POSIX_Sem_Init
    功能描述: 初始化POSIX信号量
    输入参数: INOUT SM_PosixSignal *LiShield_signal              LiShield程序的信号量
              INOUT SM_PosixSignal Algorithm_signal          算法程序的信号量
    输出参数: INOUT SM_PosixSignal *LiShield_signal              LiShield程序的信号量
              INOUT SM_PosixSignal Algorithm_signal          算法程序的信号量
    注 意 点: 目前信号量对应的文件名固定为LiShield_W、LiShield_R、Algorithm_W、Algorithm_R
***************************************************************************/
int POSIX_Sem_Init(INOUT SM_PosixSignal *pstLiShield_signal, INOUT SM_PosixSignal *pstAlgorithm_signal)
{
    pstLiShield_signal->Write = NULL;
    pstLiShield_signal->Read = NULL;
    pstAlgorithm_signal->Write = NULL;
    pstAlgorithm_signal->Read = NULL;
    
    pstLiShield_signal->Write = sem_open(LiShield_W, O_CREAT, 0777, 1);
    if (NULL == pstLiShield_signal->Write)
    {
        Printf("[MSG_CTRL]sem_open(%s) faild, error: %s\n", LiShield_W, strerror(errno));
        return ERR_COMMON_FAIL;
    }
    
    pstLiShield_signal->Read = sem_open(LiShield_R, O_CREAT, 0777, 0);
    if (NULL == pstLiShield_signal->Read)
    {
        Printf("[MSG_CTRL]sem_open(%s) faild, error: %s\n", LiShield_R, strerror(errno));
        return ERR_COMMON_FAIL;
    }
    
    pstAlgorithm_signal->Write = sem_open(Algorithm_W, O_CREAT, 0777, 1);
    if (NULL == pstAlgorithm_signal->Write)
    {
        Printf("[MSG_CTRL]sem_open(%s) faild, error: %s\n", Algorithm_W, strerror(errno));
        return ERR_COMMON_FAIL;
    }
    
    pstAlgorithm_signal->Read= sem_open(Algorithm_R, O_CREAT, 0777, 0);
    if (NULL == pstAlgorithm_signal->Read)
    {
        Printf("[MSG_CTRL]sem_open(%s) faild, error: %s\n", Algorithm_R, strerror(errno));
        return ERR_COMMON_FAIL;
    }

    return ERR_COMMON_SUCCEED;
}

共享内存初始化

/**************************************************************************
    函数名称: POSIX_ShareMem_Init
    功能描述: 初始化共享内存
    输入参数: INOUT Sharemem_Info *pstLiShield_share              LiShield程序的共享内存
              INOUT Sharemem_Info pstAlgorithm_share          算法程序的共享内存
    输出参数: INOUT Sharemem_Info *pstLiShield_share              LiShield程序的共享内存
              INOUT Sharemem_Info pstAlgorithm_share          算法程序的共享内存
    注 意 点: 目前共享内存文件名固定为LiShield_W、Algorithm_W;共享内存大小固定为40M
***************************************************************************/
int POSIX_ShareMem_Init(INOUT Sharemem_Info *pstLiShield_share, INOUT Sharemem_Info *pstAlgorithm_share)
{
    int shmid = 0;
    
    if ((NULL == pstLiShield_share) || (NULL == pstAlgorithm_share))
    {
        Printf("[MSG_CTRL]Invalid parameter\n");
        return ERR_COMMON_INVALID_PARAM;
    }

    /* 初始化LiShield程序的共享内存 */
    shmid = shm_open(LiShield_W, O_CREAT|O_RDWR, 0777);
    if (shmid < 0)
    {
        Printf("[MSG_CTRL]shm_open() error: %s\n", strerror(errno));
        return ERR_COMMON_FAIL;
    }
    
    ftruncate(shmid, SHAREMEM_SIZE_MAX);
    pstLiShield_share->szie = SHAREMEM_SIZE_MAX;
    pstLiShield_share->pShmsendbuf = mmap(NULL, SHAREMEM_SIZE_MAX, PROT_READ|PROT_WRITE, MAP_SHARED, shmid, 0);
    if (NULL == pstLiShield_share->pShmsendbuf)
    {
        Printf("[MSG_CTRL]mmap failed\n");
        //shm_unlink(pstLiShield_share->name);
        return ERR_COMMON_FAIL;
    }
    
    pstLiShield_share->shmid = shmid;

    /* 初始化算法程序的共享内存 */
    shmid = shm_open(Algorithm_W, O_CREAT|O_RDWR, 0777);
    if (shmid < 0)
    {
        Printf("[MSG_CTRL]shm_open() error: %s\n", strerror(errno));
        return ERR_COMMON_FAIL;
    }
    
    ftruncate(shmid, SHAREMEM_SIZE_MAX);
    pstAlgorithm_share->szie = SHAREMEM_SIZE_MAX;
    pstAlgorithm_share->pShmsendbuf = mmap(NULL, SHAREMEM_SIZE_MAX, PROT_READ|PROT_WRITE, MAP_SHARED, shmid, 0);
    if (NULL == pstAlgorithm_share->pShmsendbuf)
    {
        Printf("[MSG_CTRL]mmap failed\n");
        //shm_unlink(pstAlgorithm_share->name);
        return ERR_COMMON_FAIL;
    }
    
    pstAlgorithm_share->shmid = shmid;
    
    return ERR_COMMON_SUCCEED;
}

发送接收信息

/**************************************************************************
    函数名称: LiShieldSendMsg
    功能描述: LiShield程序发送消息
    输入参数: IN IPC_Info *pstIpcInfo                       进程间通信相关结构
              INOUT MSG_Info *pstMsgInfo                消息结构体
    输出参数: 
    注 意 点: 
***************************************************************************/
int LiShieldSendMsg(IN IPC_Info *pstIpcInfo, IN MSG_Info *pstMsgInfo)
{
    int MsgStatusCode = ERR_COMMON_FAIL;
    struct timespec stTime;
    MSG_Info *pstMsgInfoTmp = NULL;

    memset(&stTime, 0, sizeof(stTime));
    
    if ((NULL == pstIpcInfo) || 
        (NULL == pstIpcInfo->LiShield_signal.Write) ||
        (NULL == pstIpcInfo->Algorithm_signal.Read) ||
        (NULL == pstMsgInfo) ||
        ((sizeof(MSG_Info) + pstMsgInfo->DataLen) > pstIpcInfo->LiShield_share.szie))
    {
        Printf("[MSG_CTRL]Invalid parameter");
        return ERR_COMMON_INVALID_PARAM;
    }
    
    Printf("[MSG_CTRL]LiShield Send Msg begin, MsgType[%d], MsgCmd[%d]", pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);

    /* 等待LiShield程序可以写共享内存的信号量, 使用sem_timedwait--固定超时时间为120s, 避免出现另一个进程状态异常导致本进程阻塞 */
    //sem_wait(pstIpcInfo->LiShield_signal.Write);
    Set_SemTimeOut(&stTime);
    if (0 != sem_timedwait(pstIpcInfo->LiShield_signal.Write, &stTime))
    {
        Printf("[MSG_CTRL]sem_timedwait failed, error:%s", strerror(errno));
        return ERR_COMMON_FAIL;
    }

    /* 先清空再拷贝,避免出现pShmsendbuf中残留数据 */
    pstMsgInfo->MsgStatusCode = ERR_COMMON_FAIL;
    memset(pstIpcInfo->LiShield_share.pShmsendbuf, 0, pstIpcInfo->LiShield_share.szie);
    memcpy(pstIpcInfo->LiShield_share.pShmsendbuf, pstMsgInfo, sizeof(MSG_Info) + pstMsgInfo->DataLen);
    
    /* LiShield程序写完后告诉算法可以读取共享内存的数据 */
    sem_post(pstIpcInfo->Algorithm_signal.Read);
    
    /* 发完消息后,等待算法程序处理完消息,嵌入式程序需要查看消息是否处理成功,以及拷贝GET类型消息返回的数据 */
    //sem_wait(pstIpcInfo->LiShield_signal.Write);
    Printf("[MSG_CTRL]LiShield wait get msg result");
    if (0 != sem_timedwait(pstIpcInfo->LiShield_signal.Write, &stTime))
    {
        /* 120s超时, 则认为另外一个进程B不存在, 则需清空共享内存, 避免出现进程B启动时读到本次发送的消息, 其实本次消息对于进程B来说属于无用消息 */
        memset(pstIpcInfo->LiShield_share.pShmsendbuf, 0, pstIpcInfo->LiShield_share.szie);
        
        Printf("[MSG_CTRL]sem_timedwait failed, error:%s", strerror(errno));
        return ERR_COMMON_FAIL;
    }
    
    usleep(1000 * 20);
    
    if (MSG_TYPE_GET == pstMsgInfo->MsgType)
    {
        memcpy(pstMsgInfo, pstIpcInfo->LiShield_share.pShmsendbuf, sizeof(MSG_Info) + pstMsgInfo->DataLen);
        MsgStatusCode = pstMsgInfo->MsgStatusCode;
    }
    else
    {
        pstMsgInfoTmp = (MSG_Info *)pstIpcInfo->LiShield_share.pShmsendbuf;
        MsgStatusCode = pstMsgInfoTmp->MsgStatusCode;
    }
    
    sem_post(pstIpcInfo->LiShield_signal.Write);
    if (ERR_COMMON_SUCCEED != MsgStatusCode)
    {
        Printf("[MSG_CTRL]send LiShield fail[%d], MsgType[%d], MsgCmd[%d]", MsgStatusCode, pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);
        return ERR_COMMON_FAIL;
    }
    
    Printf("[MSG_CTRL]LiShield Send Msg end success, MsgType[%d], MsgCmd[%d]", pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);
    return ERR_COMMON_SUCCEED;
}

/**************************************************************************
    函数名称: LiShieldMsgProc
    功能描述: LiShield程序消息处理
    输入参数: IN MSG_Info *pstMsgInfo                   消息结构体
    输出参数: 
    注 意 点: 内部根据不同的消息类型进行处理
***************************************************************************/
int LiShieldMsgProc(IN MSG_Info *pstMsgInfo)
{
    int ret = ERR_COMMON_FAIL;
    
    if ((NULL == pstMsgInfo) || (NULL == pstMsgInfo->pData))
    {
        Printf("[MSG_CTRL]Invalid parameter");
        return ERR_COMMON_INVALID_PARAM;
    }

    /* 目前只支持SET消息,后续支持其他消息则取消此判断 */
    if (MSG_TYPE_SET != pstMsgInfo->MsgType)
    {
        Printf("[MSG_CTRL]Recv Msg-->not support MsgType[%d]. MsgCmd[%d]", pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);
        return ERR_COMMON_INVALID_PARAM;
    }
    else
    {
        Printf("[MSG_CTRL]Recv Msg-->MsgType[%d], MsgCmd[%d]", pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);
    }
    
    /* 根据消息命令字处理不同的消息 */
    switch (pstMsgInfo->MsgCmd)
    {
        case 1:
        {
            /* 自己写对应消息的处理函数 */
            break;
        }
        case 2:
        {
            break;
        }
        case 3:
        {
            break;
        }
        default:
        {
            ret = ERR_COMMON_NOT_SUPPORT;
            Printf("[MSG_CTRL]not support msgcmd[%d]", pstMsgInfo->MsgCmd);
            break;
        }
    }

    if (ERR_COMMON_SUCCEED != ret)
    {
        Printf("[MSG_CTRL]msg proc fail[%d], MsgType[%d] MsgCmd[%d]", ret, pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);
    }
    
    return ret;
}

/**************************************************************************
    函数名称: LiShieldRecvMsg
    功能描述: LiShield接收消息
    输入参数: IN IPC_Info *pstIpcInfo                       进程间通信相关结构
              INOUT MSG_Info *pstMsgInfo                消息结构体
    输出参数: INOUT MSG_Info *pstMsgInfo                    消息结构体
    注 意 点: 
***************************************************************************/
int LiShieldRecvMsg(IN IPC_Info *pstIpcInfo, INOUT MSG_Info *pstMsgInfo)
{
    int ret = ERR_COMMON_FAIL;
    
    if ((NULL == pstIpcInfo) || 
        (NULL == pstIpcInfo->LiShield_signal.Read) ||
        (NULL == pstIpcInfo->Algorithm_signal.Write) ||
        (NULL == pstMsgInfo))
    {
        Printf("[MSG_CTRL]Invalid parameter");
        return ERR_COMMON_INVALID_PARAM;
    }

    while (1)
    {
        sem_wait(pstIpcInfo->LiShield_signal.Read);

        pstMsgInfo = (MSG_Info *)pstIpcInfo->Algorithm_share.pShmsendbuf;
        
        ret = LiShieldMsgProc(pstMsgInfo);
        if (ERR_COMMON_SUCCEED != ret)
        {
            Printf("[MSG_CTRL]msg proc failed[%d], MsgType[%d], MsgCmd[%d]", ret, pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);
        }
        
        pstMsgInfo->MsgStatusCode = ret;

        sem_post(pstIpcInfo->Algorithm_signal.Write);
        usleep(1000 * 10);
    }
    
    return ERR_COMMON_SUCCEED;
}


/**************************************************************************
    函数名称: AlgorithmSendMsg
    功能描述: 算法程序发送消息
    输入参数: IN IPC_Info *pstIpcInfo                       进程间通信相关结构
              INOUT MSG_Info *pstMsgInfo                消息结构体
    输出参数: 
    注 意 点: 
***************************************************************************/
int AlgorithmSendMsg(IN IPC_Info *pstIpcInfo, IN MSG_Info *pstMsgInfo)
{
    int MsgStatusCode = ERR_COMMON_FAIL;
    struct timespec stTime;
    MSG_Info *pstMsgInfoTmp = NULL;
    
    memset(&stTime, 0, sizeof(stTime));
    
    if ((NULL == pstIpcInfo) || 
        (NULL == pstIpcInfo->Algorithm_signal.Write) ||
        (NULL == pstIpcInfo->LiShield_signal.Read) ||
        (NULL == pstMsgInfo) ||
        ((sizeof(MSG_Info) + pstMsgInfo->DataLen) > pstIpcInfo->LiShield_share.szie))
    {
        Printf("[MSG_CTRL]Invalid parameter");
        return ERR_COMMON_INVALID_PARAM;
    }

    /* 等待算法程序可以写共享内存的信号量, 使用sem_timedwait--固定超时时间为120s, 避免出现另一个进程状态异常导致本进程阻塞 */
    //sem_wait(pstIpcInfo->Algorithm_signal.Write);
    Set_SemTimeOut(&stTime);
    if (0 != sem_timedwait(pstIpcInfo->Algorithm_signal.Write, &stTime))
    {
        Printf("[MSG_CTRL]sem_timedwait failed, error:%s", strerror(errno));
        return ERR_COMMON_FAIL;
    }

    /* 先清空再拷贝,避免出现pShmsendbuf中残留数据 */
    pstMsgInfo->MsgStatusCode = ERR_COMMON_FAIL;
    memset(pstIpcInfo->Algorithm_share.pShmsendbuf, 0, pstIpcInfo->Algorithm_share.szie);
    memcpy(pstIpcInfo->Algorithm_share.pShmsendbuf, pstMsgInfo, sizeof(MSG_Info) + pstMsgInfo->DataLen);
    
    /*算法程序写完后告诉LiShield程序可以读取共享内存的数据 */
    sem_post(pstIpcInfo->LiShield_signal.Read);
    
    /* 发完消息后,等待嵌入式程序处理完消息,算法程序需要查看消息是否处理成功,以及拷贝GET类型消息返回的数据 */
    //sem_wait(pstIpcInfo->Algorithm_signal.Write);
    if (0 != sem_timedwait(pstIpcInfo->Algorithm_signal.Write, &stTime))
    {
        /* 120s超时, 则认为另外一个进程B不存在, 则需清空共享内存, 避免出现进程B启动时读到本次发送的消息, 其实本次消息对于进程B来说属于无用消息 */
        memset(pstIpcInfo->Algorithm_share.pShmsendbuf, 0, pstIpcInfo->Algorithm_share.szie);
        
        Printf("[MSG_CTRL]sem_timedwait failed, error:%s", strerror(errno));
        return ERR_COMMON_FAIL;
    }
    
    usleep(1000 * 20);
    
    if (MSG_TYPE_GET == pstMsgInfo->MsgType)
    {
        memcpy(pstMsgInfo, pstIpcInfo->Algorithm_share.pShmsendbuf, sizeof(MSG_Info) + pstMsgInfo->DataLen);
        MsgStatusCode = pstMsgInfo->MsgStatusCode;
    }
    else
    {
        pstMsgInfoTmp = (MSG_Info *)pstIpcInfo->Algorithm_share.pShmsendbuf;
        MsgStatusCode = pstMsgInfoTmp->MsgStatusCode;
    }
    
    sem_post(pstIpcInfo->Algorithm_signal.Write);
    
    if (ERR_COMMON_SUCCEED != MsgStatusCode)
    {
        Printf("[MSG_CTRL]send Algorithm fail[%d], MsgType[%d], MsgCmd[%d]", MsgStatusCode, pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);
        return ERR_COMMON_FAIL;
    }

    return ERR_COMMON_SUCCEED;
}

/**************************************************************************
    函数名称: AlgorithmMsgProc
    功能描述: 算法程序消息处理
    输入参数: IN MSG_Info *pstMsgInfo                   消息结构体
    输出参数: 
    注 意 点: 内部根据不同的消息类型进行处理
***************************************************************************/
int AlgorithmMsgProc(IN MSG_Info *pstMsgInfo)
{
    int ret = ERR_COMMON_FAIL;
    
    if ((NULL == pstMsgInfo) || (NULL == pstMsgInfo->pData))
    {
        Printf("[MSG_CTRL]Invalid parameter");
        return ERR_COMMON_INVALID_PARAM;
    }
    
    /* 目前只支持SET消息,后续支持其他消息则取消此判断 */
    if (MSG_TYPE_SET != pstMsgInfo->MsgType)
    {
        Printf("[MSG_CTRL]not support MsgType[%d]. MsgCmd[%d]", pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);
        return ERR_COMMON_INVALID_PARAM;
    }
    else
    {
        Printf("[MSG_CTRL]MsgType[%d], MsgCmd[%d]", pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);
    }

    /* 根据消息类型处理不同的消息 */
    switch (pstMsgInfo->MsgCmd)
    {
        case 1:
        {
            /* 自己写处理函数 */
            break;
        }
        case 2:
        {
            break;
        }
        case 3:
        {
            break;
        }
        default:
        {
            ret = ERR_COMMON_NOT_SUPPORT;
            Printf("[MSG_CTRL]not support msgcmd[%d]", pstMsgInfo->MsgCmd);
            break;
        }
    }
    
    return ret;
}

/**************************************************************************
    函数名称: AlgorithmRecvMsg
    功能描述: 算法程序接收消息
    输入参数: IN IPC_Info *pstIpcInfo                       进程间通信相关结构
              INOUT MSG_Info *pstMsgInfo                消息结构体
    输出参数: INOUT MSG_Info *pstMsgInfo                    消息结构体
    注 意 点: 
***************************************************************************/
int AlgorithmRecvMsg(IN IPC_Info *pstIpcInfo, INOUT MSG_Info *pstMsgInfo)
{
    int ret = ERR_COMMON_FAIL;
    
    if ((NULL == pstIpcInfo) || 
        (NULL == pstIpcInfo->Algorithm_signal.Read) ||
        (NULL == pstIpcInfo->LiShield_signal.Write) ||
        (NULL == pstMsgInfo))
    {
        Printf("[MSG_CTRL]Invalid parameter");
        return ERR_COMMON_INVALID_PARAM;
    }

    while (1)
    {
        sem_wait(pstIpcInfo->Algorithm_signal.Read);

        pstMsgInfo = (MSG_Info *)pstIpcInfo->LiShield_share.pShmsendbuf;
        ret = AlgorithmMsgProc(pstMsgInfo);
        if (ERR_COMMON_SUCCEED != ret)
        {
            Printf("[MSG_CTRL]msg proc failed[%d], MsgType[%d], MsgCmd[%d]\n", ret, pstMsgInfo->MsgType, pstMsgInfo->MsgCmd);
        }
        
        pstMsgInfo->MsgStatusCode = ret;
        sem_post(pstIpcInfo->LiShield_signal.Write);
        usleep(1000 * 10);
    }
    
    return ERR_COMMON_SUCCEED;
}

相关定义

#define LiShield_W                    "LiShield_W2_Algorithm"             /* LiShield写数据有名信号量。LiShield写完需要告诉算法共享内存可读了,需要sem_post(Algorithm_R)  */
#define LiShield_R                    "LiShield_R"                        /* LiShield读数据有名信号量。LiShield读完需要告诉算法共享内存可写了, 需要sem_post(Algorithm_W) */

#define Algorithm_W                   "Algorithm_W2_LiShield"             /* Algorithm写数据信号量 */
#define Algorithm_R                   "Algorithm_R"                       /* Algorithm读数据信号量 */

/* 与共享内存相关的信号量 */
typedef struct sharemem_signal
{
    sem_t *Write;                   /* 是否可写的信号量,为1表示可写 */
    sem_t *Read;                    /* 是否可读的信号量,为1表示可读 */
}SM_PosixSignal;

/* 共享内存信息 */
typedef struct sharemem_info
{
    char name[128];                 /* POSIX 共享内存标识, 比如LiShield_W */
    int szie;                       /* 共享内存大小 */
    int shmid;                      /* 创建共享内存成功后系统返回的文件标识符 */
    void *pShmsendbuf;              /* 共享内存对应的内存空间 */
}Sharemem_Info;

/* 进程间通信交互信息 */
typedef struct POSIXSharemem_signal
{
    SM_PosixSignal LiShield_signal;                 /* LiShield程序的信号量 */
    Sharemem_Info LiShield_share;                   /* LiShield程序的共享内存信息 */
    SM_PosixSignal Algorithm_signal;                /* 算法程序的信号量 */
    Sharemem_Info Algorithm_share;                  /* 算法程序的共享内存信息 */
}IPC_Info;

/* 消息结构体信息 */
typedef struct msginfo
{
    int MsgType;                    /* 消息类型: MSG_Type */
    int MsgCmd;                     /* 消息命令字 */
    int FirstChannel;               /* 第一通道 */
    int SecondChannel;              /* 第二通道 */
    int ThirdChannel;               /* 第三通道 */
    int SubChannel;                 /* 子通道 */
    int MsgStatusCode;              /* 消息处理结果码 */
    int DataLen;                    /* 消息大小 */
    char pData[0];                  /* 消息内容, 可变长数组; 此处使用指针的话, 内存空间不连续 消息不好拷贝, 因此不使用指针 */
}MSG_Info;

/* 消息类型 */
typedef enum MsgType {
    MSG_TYPE_GET,
    MSG_TYPE_SET,
    MSG_TYPE_NOTIFY,
}MSG_Type;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值