Makefile模板和工程模板(消息队列和共享内存)的使用

news2024/9/20 18:01:36

一、 Makefile模板

#指定生成的文件名
OJB_OUT = test

#指定每一个c文件对应的.o文件
OBJS = a.o b.o main.o

#指定编译器
CC = gcc

#指定需要的库
ULDFLAGS = 

###########################################
#以下的内容不需要修改
###########################################
all:$(OJB_OUT)

$(OJB_OUT):$(OBJS)
	$(CC) -o $@ $^ $(ULDFLAGS)

dep_files := $(foreach f,$(OBJS),.$(f).d)
dep_files := $(wildcard $(dep_files))

ifneq ($(dep_files),)
  include $(dep_files)
endif

$(OBJS):%.o:%.c
	$(CC) -Wp,-MD,.$@.d -c $< -o $@
    
clean:
	rm -rf .*.o.d *.o $(OJB_OUT)

二、 工程模板(消息队列和共享内存)

1. pub_define.h

/***********************************************************************************
Description:    类型重定义
***********************************************************************************/
#ifndef __PUB_DEFINE_H
#define __PUB_DEFINE_H

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>

#define MAX_PROC_NAME_SZ    32

#define MAX_PATH_LEN 256  //最大路径长度

#ifdef BOOL
#undef BOOL
#endif

#ifdef FALSE
#undef FALSE
#endif

#ifdef TRUE
#undef TRUE
#endif

#define BOOL    int
#define FALSE   (0)
#define TRUE    (!FALSE)

#define KB 1024
#define MB (1024*KB)
#define GB (1024*MB)

#define UNUSED(x) (void)x;  //仅仅为了消除警告用,可解决未定义变量

#include <stdint.h>

#define uint8  uint8_t
#define uint16 uint16_t
#define uint32 uint32_t

#define int8  int8_t
#define int16 int16_t
#define int32 int32_t

#define SLEEP_MS(ms) usleep(ms*1000)

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))

#endif //__PUB_DEFINE_H

2. msg_queue_peer.h

/***********************************************************************************
Description:    点对点型消息队列组件
***********************************************************************************/

#ifndef MSG_QUEUE_PEER_H
#define MSG_QUEUE_PEER_H

#include "pub_define.h"
#include <sys/ipc.h>
#include <sys/msg.h>

int msg_queue_send(const char *name, const void *msg, size_t msgsz, int msgflg);
int msg_queue_recv(const char *name, void *msg, size_t msgsz, long msgtyp, int msgflg);

#endif  // MSG_QUEUE_PEER_H

3. shmem.h

/***********************************************************************************
Description:    提供共享内存组件
***********************************************************************************/

#ifndef SHMEM_H
#define SHMEM_H

#include "pub_define.h"
#include <sys/ipc.h>
#include <sys/shm.h>

#define SHM_NAME_SZ    32

struct shm_param
{
    int id;                       //共享内存ID
    size_t size;
    void *addr;                   //共享内存地址
    char name[SHM_NAME_SZ+1];     //共享内存key标识
};

int shm_init(struct shm_param *para, const char *name, size_t size);
void *shm_getaddr(struct shm_param *para);
void shm_write(const struct shm_param *para, void *data, size_t size);
int shm_del(const struct shm_param *para);

#endif  // SHMEM_H

4. msg_queue_peer.c

/***********************************************************************************
Description:    点对点型消息队列组件
***********************************************************************************/

#include <errno.h>
#include "msg_queue_peer.h"

#define MSG_PATH "/tmp/ipc/msgqueue/peer/"

#define MAGIC_ID 'j'

/**
 * @brief msg_queue_send
 * @param name 发送给哪个消息队列
 * @param msg 消息数据,第一个字段必须是long类型的消息类型
 * @param msgsz 整个msg大小,不需要减去long--sizeof(*msg)
 * @param msgflg 同msgsnd
 * @return 同msgsnd
 */
int msg_queue_send(const char *name, const void *msg, size_t msgsz, int msgflg)
{
    assert(NULL != name && strlen(name) > 0);
    assert(NULL != msg);

    key_t key;
    int ret;
    int msgid;
    char sys_cmd[256];
    char path[256];

    sprintf(path, "%s%s", MSG_PATH, name);

    //文件不存在创建
    if(access(path, F_OK) < 0)
    {
        sprintf(sys_cmd, "%s %s", "touch", path);
        ret = system(sys_cmd);
        UNUSED(ret);
    }

    //创建key
    key = ftok(path, MAGIC_ID);
    if(key < 0){
        perror("fail to ftok");
        return -1;
    }

    //创建消息队列
    msgid = msgget(key, IPC_CREAT|0666);
    if (msgid < 0)
    {
        perror("fail to msgget");
        return -1;
    }

    return msgsnd(msgid, msg, msgsz - sizeof(long), msgflg);
}

/**
 * @brief msg_queue_send
 * @param name 从哪个消息队列接收
 * @param msg 消息缓冲区,第一个字段必须是long类型的消息类型
 * @param msgsz 整个msg大小,不需要减去long--sizeof(*msg)
 * @param msgtyp 同msgrcv
 * @param msgflg 同msgrcv
 * @return 同msgrcv
 */
int msg_queue_recv(const char *name, void *msg, size_t msgsz, long msgtyp, int msgflg)
{
    assert(NULL != name && strlen(name) > 0);
    assert(NULL != msg);

    key_t key;
    int ret;
    int msgid;
    char sys_cmd[256];
    char path[256];

    sprintf(path, "%s%s", MSG_PATH, name);
    //文件不存在创建
    if(access(path, F_OK) < 0)
    {
        sprintf(sys_cmd, "%s %s", "touch", path);
        ret = system(sys_cmd);
        UNUSED(ret);
    }

    //创建key
    key = ftok(path, MAGIC_ID);
    if(key < 0){
        perror("fail to ftok");
        return -1;
    }

    //创建消息队列
    msgid = msgget(key, IPC_CREAT|0666);
    if (msgid < 0)
    {
        perror("fail to msgget");
        return -1;
    }

    return msgrcv(msgid, msg, msgsz - sizeof(long), msgtyp, msgflg);
}


/**
 * @brief 判断某个类型的消息是否存在,但是不取出
 * @param name 指定消息队列名
 * @param msgtyp 消息类型
 * @return TRUE FALSE
 */
BOOL msg_queue_msgexist(const char *name, long msgtyp)
{
    assert(NULL != name && strlen(name) > 0);

    key_t key;
    int ret;
    int msgid;
    char sys_cmd[256];
    char path[256];

    sprintf(path, "%s%s", MSG_PATH, name);
    //文件不存在创建
    if(access(path, F_OK) < 0)
    {
        sprintf(sys_cmd, "%s %s", "touch", path);
        ret = system(sys_cmd);
        UNUSED(ret);
    }

    //创建key
    key = ftok(path, MAGIC_ID);
    if(key < 0)
    {
        perror("fail to ftok");
        return -1;
    }

    //创建消息队列
    msgid = msgget(key, IPC_CREAT|0666);
    if (msgid < 0)
    {
        perror("fail to msgget");
        return -1;
    }

    if(msgrcv(msgid, NULL, 0, msgtyp, IPC_NOWAIT) < 0)
    {
        if(errno == E2BIG)
        {
            return TRUE;
        }
    }
    return FALSE;
}

5. shmem.c

/***********************************************************************************
Description:    提供共享内存组件
***********************************************************************************/

#include "shmem.h"

#define MAGIC_ID 'j'

/**
 * @brief 初始化共享内存
 * @param para 参数结构体,传入即可
 * @param name 共享内存标识名称
 * @return 0 -1
 */
int shm_init(struct shm_param *para, const char *name, size_t size)
{
    assert(NULL != para);
    assert(NULL != name && strlen(name) > 0);
    key_t key;
    int ret;
    int id;
    char sys_cmd[256];
    char path[256];

    sprintf(path, "/tmp/ipc/shmem/%s", name);
    sprintf(sys_cmd, "%s %s", "touch", path);
    ret = system(sys_cmd);
    UNUSED(ret);

    //创建key
    key = ftok(path, MAGIC_ID);
    if(key < 0){
        perror("fail to ftok");
        printf("error :path = %s\n", path);
        return -1;
    }

    //创建共享内存
    id = shmget(key, size, IPC_CREAT|0666);
    if (id < 0)
    {
        perror("fail to shmget");
        return -1;
    }

    para->id = id;
    para->size = size;
    strcpy(para->name, name);

    return 0;
}

/**
 * @brief 获取共享内存地址
 * @param para
 * @return 失败返回NULL
 */
void *shm_getaddr(struct shm_param *para)
{
    void *addr;
    addr = shmat(para->id, NULL, 0);
    if(addr == (void *)-1)
    {
        para->addr = NULL;
    }
    else
    {
        para->addr = addr;
    }

    return para->addr;
}

/**
 * @brief 写共享内存
 * @param para
 * @param data
 * @param size
 */
void shm_write(const struct shm_param *para, void *data, size_t size)
{
    assert(size <= para->size);
    assert(NULL != data);

    memcpy(para->addr, data, size);
}

/**
 * @brief 解除共享内存
 * @param para
 * @return
 */
int shm_del(const struct shm_param *para)
{
    assert(NULL != para);
    int ret = shmdt(para->addr);
    if(ret < 0)
    {
        perror("fail to shmdt");
        return -1;
    }

    ret = shmctl(para->id, IPC_RMID, NULL);
    if(ret < 0)
    {
        perror("fail to shmctl");
        return -1;
    }

    return 0;
}

6. main.c

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("project demo\n");

    return 0;
}

7. Makefile

#指定生成的文件名
OJB_OUT = test


#指定每一个c文件对应的.o文件
OBJS = shmem.o msg_queue_peer.o main.o


#指定编译器
CC = gcc


#指定需要的库和路径
ULDFLAGS = 


###########################################
#以下的内容不需要修改
###########################################
all:$(OJB_OUT)


$(OJB_OUT):$(OBJS)
	$(CC) -o $@ $^ $(ULDFLAGS)


dep_files := $(foreach f,$(OBJS),.$(f).d)
dep_files := $(wildcard $(dep_files))


ifneq ($(dep_files),)
  include $(dep_files)
endif


$(OBJS):%.o:%.c
	$(CC) -Wp,-MD,.$@.d -c $< -o $@
    
clean:
	rm -rf .*.o.d *.o $(OJB_OUT)

三、工程模板中通信组件的使用

以下组件依赖临时目录,必须提前创建(tmp目录是内存型目录,如果重启了系统会消失,所以每次重启后注意重新创建下)

mkdir /tmp/ipc/shmem -p
mkdir /tmp/ipc/msgqueue/peer -p

1.  消息队列

源码阅读:

(1)发送程序:

#include "msg_queue_peer.h"

struct msgbuf
{
    long mtype;
    char mdata[256];
};

int main(int argc, char *argv[])
{
    struct msgbuf send_buf;

    //这个mtype可以不用,但是必须赋一个不小于0的数
    send_buf.mtype = 1;

    while (1)
    {
        gets(send_buf.mdata, 256);

        if(msg_queue_send("topic", &send_buf, sizeof(send_buf), 0) < 0)
        {
            printf("msg_queue_send error\n");
            return -1;
        }
    }

    return 0;
}

(2)接收程序:

#include "msg_queue_peer.h"

struct msgbuf
{
    long mtype;
    char mdata[256];
};

int main(int argc, char *argv[])
{
    struct msgbuf recv_buf;

    while (1)
    {
        if(msg_queue_recv("topic", &recv_buf, sizeof(recv_buf), 0, 0) > 0)
        {
            printf("recv from msga type = %ld\n", recv_buf.mtype);
            printf("recv from msga data = %s\n", recv_buf.mdata);
        }
        else
        {
            perror("recv error:");
            return -1;
        }
    }

    return 0;
}

2. 共享内存

(1)写入共享内存

#include "shmem.h"

static struct shm_param para;

struct student
{
    int num;
    char name[64];
};

int main(int argc, char *argv[])
{
    int ret = -1;

    ret = shm_init(&para, "shm_test", 1024);
    if(ret < 0)
    {
        return -1;
    }

    struct student *addr = shm_getaddr(&para);
    if(addr == NULL)
    {
        return -1;
    }

    addr->num = 10;
    strcpy(addr->name, "zhangsan");

    return 0;
}

(2)读取共享内存

#include "shmem.h"

static struct shm_param para;

struct student
{
    int num;
    char name[64];
};

int main(int argc, char *argv[])
{
    int ret = -1;

    ret = shm_init(&para, "shm_test", 1024);
    if(ret < 0)
    {
        return -1;
    }

    struct student *addr = shm_getaddr(&para);
    if(addr == NULL)
    {
        return -1;
    }

    printf("num = %d\n", addr->num);
    printf("num = %s\n", addr->name);

    shm_del(&para);

    return 0;
}

3. 共享内存中读写结构体数组的使用

  假设学生信息结构体定义如下:

struct student
{
    int num;
    char name[16];
}

定义a、b两个进程,a进程创建若干个(个数自己决定,是可变的)学生,填充任意的信息,通过共享内存将学生信息共享给b进程(包括学生个数)。b进程拿到信息后打印到终端。

提示:这里可巧妙的利用指针的操作,先申请足够大的共享内存,映射后然后通过不同类型的指针来操作和读取内容中的数据。模型图如下:

(1)共享内存写入结构体数组和大小

#include "shmem.h"

static struct shm_param para;

struct student
{
    int num;
    char name[64];
};

static int *total;  //指向共享内存中数据节点总个数
static struct student *node_arr;  //指向共享内存中节点缓存数组头

#define MAX_NODE 128  //最大支持学生数目
#define STD_NODE_LEN sizeof(struct student)
#define MAX_NODE_SIZE (MAX_NODE * STD_NODE_LEN)

int main(int argc, char *argv[])
{
    int ret = -1;

    ret = shm_init(&para, "shm_test", MAX_NODE_SIZE);
    if(ret < 0)
    {
        return -1;
    }

    void *node_p = shm_getaddr(&para);
    if(node_p == NULL)
    {
        return -1;
    }

    memset(node_p, 0, MAX_NODE_SIZE);

    //前4个字节存储实际的学生数目
    total = (int *)node_p;
    //后面空间存储数据点
    node_arr = (struct student *)(node_p + sizeof(int));

    *total = 3;  //假设有3个人

    //第1个人赋值
    node_arr[0].num = 1;
    strcpy(node_arr[0].name, "zhangsan");

    //第2个人赋值
    node_arr[1].num = 2;
    strcpy(node_arr[1].name, "lisi");

    //第3个人赋值
    node_arr[2].num = 3;
    strcpy(node_arr[2].name, "wangwu");

    return 0;
}

 (2)共享内存读取结构体数组

#include "shmem.h"

static struct shm_param para;

struct student
{
    int num;
    char name[64];
};

static int *total;  //指向共享内存中数据节点总个数
static struct student *node_arr;  //指向共享内存中节点缓存数组头

#define MAX_NODE 128  //最大支持学生数目
#define STD_NODE_LEN sizeof(struct student)
#define MAX_NODE_SIZE (MAX_NODE * STD_NODE_LEN)

int main(int argc, char *argv[])
{
    int ret = -1;

    ret = shm_init(&para, "shm_test", MAX_NODE_SIZE);
    if(ret < 0)
    {
        return -1;
    }


    void *node_p = shm_getaddr(&para);
    if(node_p == NULL)
    {
        return -1;
    }

    //前4个字节存储实际的学生数目
    total = (int *)node_p;
    //后面空间存储数据点
    node_arr = (struct student *)(node_p + sizeof(int));

    printf("num = %d\n", *total);
    int i;
    for(i=0; i<*total; i++)
    {
        printf("num=%d, name=%s\n", \
               node_arr[i].num,\
               node_arr[i].name);
    }

    //这个接口只有在这块共享内存不用了才能删除,项目中如果一直使用,不要调用这个接口
    shm_del(&para);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/821006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

行业追踪,2023-08-01

自动复盘 2023-08-01 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

leetcode-143-重排链表

题意描述&#xff1a; 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为&#xff1a; L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值&#xff0c;而是需要…

cmake+pybind11打包c++库成python wheel安装包

目录 写在前面准备1、pybind11获取源码编译安装 2、conda demo官方源码修改CMakeLists.txt编译生成安装测试 参考完 写在前面 1、本文内容 有时候我们需要用c代码&#xff0c;供python调用&#xff0c;本文提供将c库封装成python接口的方法&#xff0c;并将库打包成可通过pip安…

Apikit 自学日记:API 异常监控-创建 API 监控

如何在apikit中&#xff0c;创建 API 监控呢&#xff1f; 创建并开启监控API 一、手动创建监控API Eolink API 网络监控平台支持从 Eolink API Management&#xff08;API管理产品&#xff09;中导入API信息&#xff0c;或者手动创建监控API。 进入API监控页面&#xff0c;点击…

23款奔驰S450 4MATIC升级原厂流星雨智能数字大灯,让智能照亮您前行的路

凭借智能数字大灯 (DIGITAL LIGHT)&#xff0c;您可体验根据其他道路使用者和周围环境进行优化调节的理想照明条件。这款包含130万像素模块大灯&#xff0c;进一步扩展了几何多光束 LED 大灯的功能。其高分辨率的照明可有针对性地点亮各个区域。解锁车辆时&#xff0c;大灯将通…

快速制作美容行业预约小程序

随着科技的不断进步&#xff0c;移动互联网的快速发展&#xff0c;小程序成为了很多行业迅速发展的利器。对于美容行业来说&#xff0c;一款美容预约小程序不仅可以方便用户进行预约&#xff0c;还可以提升美容店铺的服务质量和管理效率。下面&#xff0c;我们来介绍一下如何快…

23 设计模式(详细介绍附DEMO)

设计模式在Java中的应用与实现 &#x1f680;&#x1f680;&#x1f680;1.创建型模式1. 工厂方法模式&#xff08;Factory Pattern&#xff09;2.抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;3. 单例模式&#xff08;Singleton Pattern&#xff09;4.原型模…

rfid资产盘点管理系统软件

很多企业开始规划固定资产的总结&#xff0c;或者现在开始总结资产。面对众多不同种类的固定资产&#xff0c;总结已经成为一项工程量大、耗时长的任务。采用轻松的RFID固定资产管理系统后&#xff0c;可以大大提高这种总结工作的效率&#xff0c;获得比过去更清晰的资产清单和…

三菱plcCCLINK转profinet与西门子PLC通讯案例分析

用三菱PLC的控制系统需要和西门子的PLC控制系统交互数据&#xff0c;捷米JM-PN-CCLK 是自主研发的一款 PROFINET 从站功能的通讯网关。该产品主要功能是将各种 CCLINK 总线和 PROFINET 网络连接起来。 捷米JM-PN-CCLK总线中做为从站使用&#xff0c;连接到 CCLINK 总线中做为…

【C++】基于多设计模式下的同步异步日志系统

✍作者&#xff1a;阿润021 &#x1f4d6;专栏&#xff1a;C 文章目录 一、项目介绍二、项目实现准备工作1.日志系统技术实现策略2.相关技术知识补充2.1 不定参函数设计2.2 设计模式 三、日志项目框架设计1.模块划分2.各模块关系图 四、详细代码实现1.实用工具类设计2.日志等级…

StampedLock使用及源码分析:号称比读写锁还要快的锁

文章目录 一、StampedLock锁概述1、StampedLock锁简介2、ReentrantReadWriteLock回顾3、ReentrantReadWriteLock导致锁饥饿问题4、锁饥饿问题的缓解5、StampedLock与ReentrantReadWriteLock的对比6、StampedLock特点7、StampedLock的缺点 二、StampedLock的使用1、StampedLock的…

基于PHP校园疫情防控信息管理系统-计算机毕设 附源码12057

PHP校园疫情防控信息管理系统 摘 要 如今计算机行业的发展极为快速&#xff0c;搭载于计算机软件运行的数据库管理系统在各行各业得到了广泛的运用&#xff0c;其在数据管理方面具有的准确性和高效性为大中小企业的日常运营提供了巨大的帮助。自从2020年新冠疫情爆发以来&…

ArduPilot H743 Dual BMI270 Mark4 四轴DIY简单功能验证

ArduPilot H743 Dual BMI270 Mark4 四轴DIY简单功能验证 1. 源由2. 梳理2.1 基本配置2.2 滤波配置2.3 FPV-VTX配置2.4 FPV操控2.5 自适应PID调参2.6 电传配置 3. 视频3.1 FPV操控性3.2 路点巡航3.3 救援模式 4. 总结5. 参考资料6. 补充说明--问题集中回答 1. 源由 基于Mark4机…

易上手的数据报表工具有哪些?奥威BI零编程

易上手的数据报表功能有哪些&#xff1f;实际上&#xff0c;国产的BI报表工具都算得上是易上手的&#xff0c;因为它们大多都是低代码的BI报表工具&#xff0c;只需掌握基础SQL即可。但奥威BI报表工具却是零编程做大数据分析的BI报表工具。要说易上手&#xff0c;奥威BI报表工具…

Spark-统一内存模型

总结&#xff1a; Spark的内存模型分为4部分&#xff0c;分别是存储内存&#xff0c;计算内存&#xff0c;其他内存&#xff0c;预留内存&#xff1b; 其中存储内存和计算内存可以动态占用&#xff0c;当己方内存不足对方空余则可占用对方的内存&#xff0c;计算内存被存储内…

Attention机制竟有bug,Softmax是罪魁祸首,影响所有Transformer

大模型开发者&#xff0c;你们错了&#xff01; 「我发现注意力公式里有个 bug&#xff0c;八年了都没有人发现。所有 Transformer 模型包括 GPT、LLaMA 都受到了影响。」 昨天&#xff0c;一位名叫 Evan Miller 的统计工程师的话在 AI 领域掀起了轩然大波。 我们知道&#x…

解决单节点es索引yellow

现象 单节点的es&#xff0c;自动创建索引后&#xff0c;默认副本个数为1&#xff0c;索引状态为yellow 临时解决 修改副本个数为0 永久解决 方法1、修改elasticsearch.yml文件&#xff0c;添加配置并重启es number_of_replicas&#xff1a;副本分片数&#xff0c;默认…

UG\NX二次开发 创建分割面、细分面

文章作者:里海 来源网站:https://blog.csdn.net/WangPaiFeiXingYuan 简介: 群友问“UF没有分割面吗” 这个是有的,下面就是分割面(细分面)的演示效果和c++源代码。 效果: 代码: #include "me.hpp" #include <stdio.h> #include <string.h> #i…

财报解读:英特尔二季度业绩回暖,IFS业务增长势能已然释放?

英特尔终于看到了盈利曙光。 北京时间7月28日&#xff0c;英特尔公布了2023财年第二季度财报&#xff0c;数据显示公司业绩超出市场预期&#xff0c;财报一经发布&#xff0c;第二个交易日英特尔股价上涨6.6%&#xff0c;最终报收36.83美元。 &#xff08;图片来源&#xff1a…

挪威网络安全大危机?数据备份刻不容缓

挪威国家安全局近期确认&#xff0c;黑客利用Ivanti Endpoint Manager Mobile&#xff08;EPMM&#xff09;解决方案中的零日漏洞对多个软件平台进行攻击&#xff0c;访问并窃取了受感染系统中的敏感数据&#xff0c;导致出现数据泄露问题。 此次零日漏洞&#xff08;CVE-2023-…