应用——基于Linux内核链表和线程的邮箱系统

基于Linux内核链表和线程的邮箱系统完整实现

一、项目概述与架构

这是一个基于Linux内核风格双向链表实现的线程间通信邮箱系统 。系统采用生产者-消费者模型,使用队列作为消息缓冲区,支持多线程间的异步消息传递

系统架构图

复制代码
┌─────────────────────────────────────────────┐
│             邮箱系统 (MBS)                   │
│  ┌─────────────────────────────────────┐    │
│  │       线程链表 (list_head)           │    │
│  │  ┌─────┐  ┌─────┐  ┌─────┐  ...    │    │
│  │  │线程1│←→│线程2│←→│线程3│←→...    │    │
│  │  └─────┘  └─────┘  └─────┘          │    │
│  │     │         │         │            │    │
│  │  ┌──┴──┐  ┌──┴──┐  ┌──┴──┐          │    │
│  │  │队列1│  │队列2│  │队列3│          │    │
│  │  └─────┘  └─────┘  └─────┘          │    │
│  └─────────────────────────────────────┘    │
│          ↑              ↑                    │
│          │              │                    │
│     send_msg()     recv_msg()               │
│          │              │                    │
│      ┌───┴──┐      ┌───┴──┐                 │
│      │生产者│      │消费者│                 │
│      └──────┘      └──────┘                 │
└─────────────────────────────────────────────┘

二、完整代码实现

1. 链表头文件 list.h

cpp 复制代码
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H

#include <linux/stddef.h>
#include <stdio.h>

#define LIST_POISON1 ((void *)0)
#define LIST_POISON2 ((void *)0)

// 计算结构体成员的偏移量
#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)

// 通过成员指针获取结构体指针
#define container_of(ptr, type, member)                    \
    ({                                                     \
        const typeof(((type *)0)->member) *__mptr = (ptr); \
        (type *)((char *)__mptr - offsetof(type, member)); \
    })

// 双向链表节点
struct list_head {
    struct list_head *next, *prev;
};

// 链表头初始化宏
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)

// 初始化链表头
static inline void INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list;
    list->prev = list;
}

// 内部链表添加函数
static inline void __list_add(struct list_head *new, struct list_head *prev,
                              struct list_head *next)
{
    next->prev = new;
    new->next = next;
    new->prev = prev;
    prev->next = new;
}

// 在头部添加节点(适合实现栈)
static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}

// 在尾部添加节点(适合实现队列)
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
    __list_add(new, head->prev, head);
}

// 内部链表删除函数
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
    next->prev = prev;
    prev->next = next;
}

// 删除节点
static inline void list_del(struct list_head *entry)
{
    __list_del(entry->prev, entry->next);
    entry->next = LIST_POISON1;
    entry->prev = LIST_POISON2;
}

// 删除并重新初始化节点
static inline void list_del_init(struct list_head *entry)
{
    __list_del(entry->prev, entry->next);
    INIT_LIST_HEAD(entry);
}

// 检查链表是否为空
static inline int list_empty(const struct list_head *head)
{
    return head->next == head;
}

// 检查是否是链表的最后一个节点
static inline int list_is_last(const struct list_head *list,
                               const struct list_head *head)
{
    return list->next == head;
}

// 检查链表是否只有一个节点
static inline int list_is_singular(const struct list_head *head)
{
    return !list_empty(head) && (head->next == head->prev);
}

// 替换节点
static inline void list_replace(struct list_head *old, struct list_head *new)
{
    new->next = old->next;
    new->next->prev = new;
    new->prev = old->prev;
    new->prev->next = new;
}

// 移动节点到另一个链表的头部
static inline void list_move(struct list_head *list, struct list_head *head)
{
    __list_del(list->prev, list->next);
    list_add(list, head);
}

// 移动节点到另一个链表的尾部
static inline void list_move_tail(struct list_head *list,
                                  struct list_head *head)
{
    __list_del(list->prev, list->next);
    list_add_tail(list, head);
}

// 连接两个链表
static inline void __list_splice(const struct list_head *list,
                                 struct list_head *prev, struct list_head *next)
{
    struct list_head *first = list->next;
    struct list_head *last = list->prev;

    first->prev = prev;
    prev->next = first;

    last->next = next;
    next->prev = last;
}

// 将list链表连接到head后面
static inline void list_splice(const struct list_head *list,
                               struct list_head *head)
{
    if (!list_empty(list))
        __list_splice(list, head, head->next);
}

// 将list链表连接到head前面
static inline void list_splice_tail(struct list_head *list,
                                    struct list_head *head)
{
    if (!list_empty(list))
        __list_splice(list, head->prev, head);
}

// ================== 遍历宏 ==================

// 基本遍历(不安全,遍历时不能删除节点)
#define list_for_each(pos, head) \
    for (pos = (head)->next; pos != (head); pos = pos->next)

// 安全遍历(遍历时可以删除节点)
#define list_for_each_safe(pos, n, head)                   \
    for (pos = (head)->next, n = pos->next; pos != (head); \
         pos = n, n = pos->next)

// 反向安全遍历
#define list_for_each_prev_safe(pos, n, head) \
    for (pos = (head)->prev, n = pos->prev;   \
         pos != (head); pos = n, n = pos->prev)

// 通过链表节点获取包含它的结构体
#define list_entry(ptr, type, member) container_of(ptr, type, member)

// 获取链表的第一个元素
#define list_first_entry(ptr, type, member) \
    list_entry((ptr)->next, type, member)

// 遍历包含链表节点的结构体
#define list_for_each_entry(pos, head, member)                 \
    for (pos = list_entry((head)->next, typeof(*pos), member); \
         &pos->member != (head);                               \
         pos = list_entry(pos->member.next, typeof(*pos), member))

// 安全遍历包含链表节点的结构体(可删除)
#define list_for_each_entry_safe(pos, n, head, member)          \
    for (pos = list_entry((head)->next, typeof(*pos), member),  \
        n = list_entry(pos->member.next, typeof(*pos), member); \
         &pos->member != (head);                                \
         pos = n, n = list_entry(n->member.next, typeof(*n), member))

// 从当前点继续遍历
#define list_for_each_entry_continue(pos, head, member)            \
    for (pos = list_entry(pos->member.next, typeof(*pos), member); \
         &pos->member != (head);                                   \
         pos = list_entry(pos->member.next, typeof(*pos), member))

// 反向遍历包含链表节点的结构体
#define list_for_each_entry_reverse(pos, head, member)         \
    for (pos = list_entry((head)->prev, typeof(*pos), member); \
         &pos->member != (head);                               \
         pos = list_entry(pos->member.prev, typeof(*pos), member))

// ================== 哈希链表 ==================

// 哈希链表头(单指针)
struct hlist_head {
    struct hlist_node *first;
};

// 哈希链表节点
struct hlist_node {
    struct hlist_node *next, **pprev;
};

// 初始化哈希链表头
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)

// 初始化哈希链表节点
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
    h->next = NULL;
    h->pprev = NULL;
}

// 检查哈希链表是否为空
static inline int hlist_empty(const struct hlist_head *h)
{
    return !h->first;
}

// 检查哈希链表节点是否未链接
static inline int hlist_unhashed(const struct hlist_node *h)
{
    return !h->pprev;
}

// 删除哈希链表节点
static inline void hlist_del(struct hlist_node *n)
{
    struct hlist_node *next = n->next;
    struct hlist_node **pprev = n->pprev;
    *pprev = next;
    if (next)
        next->pprev = pprev;
    n->next = LIST_POISON1;
    n->pprev = LIST_POISON2;
}

// 删除并重新初始化哈希链表节点
static inline void hlist_del_init(struct hlist_node *n)
{
    if (!hlist_unhashed(n)) {
        hlist_del(n);
        INIT_HLIST_NODE(n);
    }
}

// 在哈希链表头部添加节点
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
    struct hlist_node *first = h->first;
    n->next = first;
    if (first)
        first->pprev = &n->next;
    h->first = n;
    n->pprev = &h->first;
}

// 哈希链表遍历宏
#define hlist_for_each(pos, head) \
    for (pos = (head)->first; pos; pos = pos->next)

// 哈希链表安全遍历宏
#define hlist_for_each_safe(pos, n, head)        \
    for (pos = (head)->first; pos && ({          \
                                  n = pos->next; \
                                  1;             \
                              });                \
         pos = n)

// 遍历哈希链表获取包含结构体
#define hlist_for_each_entry(tpos, pos, head, member)                          \
    for (pos = (head)->first; pos && ({                                        \
                                  tpos =                                       \
                                      hlist_entry(pos, typeof(*tpos), member); \
                                  1;                                           \
                              });                                              \
         pos = pos->next)

// 哈希链表安全遍历获取包含结构体
#define hlist_for_each_entry_safe(tpos, pos, n, head, member)                  \
    for (pos = (head)->first; pos && ({                                        \
                                  n = pos->next;                               \
                                  1;                                           \
                              }) &&                                            \
                              ({                                               \
                                  tpos =                                       \
                                      hlist_entry(pos, typeof(*tpos), member); \
                                  1;                                           \
                              });                                              \
         pos = n)

#endif /* _LINUX_LIST_H */

2. 队列头文件 linkque.h

cpp 复制代码
#ifndef _LINKQUE_H_
#define _LINKQUE_H_

#include <pthread.h>

// 邮件数据结构
typedef struct mail_data {
    pthread_t id_of_sender;      // 发送者线程ID
    char name_of_sender[256];    // 发送者名称
    pthread_t id_of_recver;      // 接收者线程ID
    char name_of_recver[256];    // 接收者名称
    char data[256];             // 消息内容
} MAIL_DATA;

typedef MAIL_DATA DATATYPE;     // 队列数据类型

// 队列节点结构
typedef struct quenode {
    DATATYPE data;              // 数据
    struct quenode *next;       // 下一个节点指针
} LinkQueNode;

// 队列结构
typedef struct _linkque {
    LinkQueNode *head;          // 队头指针
    LinkQueNode *tail;          // 队尾指针
    int clen;                   // 当前队列长度
} LinkQue;

// ================== 队列操作接口 ==================

// 创建队列
LinkQue *CreateLinkQue();

// 入队操作
int EnterLinkQue(LinkQue *lq, DATATYPE *newdata);

// 出队操作
int QuitLinkQue(LinkQue *lq);

// 获取队头元素(不删除)
DATATYPE *GetHeadLinkQue(LinkQue *lq);

// 获取队列大小
int GetSizeLinkQue(LinkQue *lq);

// 检查队列是否为空
int IsEmptyLinkQue(LinkQue *lq);

// 销毁队列
int DestroyLinkQue(LinkQue *lq);

#endif /* _LINKQUE_H_ */

3. 队列实现 linkque.c

cpp 复制代码
#include "linkque.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 创建空队列
LinkQue *CreateLinkQue()
{
    LinkQue *lq = (LinkQue *)malloc(sizeof(LinkQue));
    if (NULL == lq) {
        printf("CreateLinkQue malloc error\n");
        return NULL;
    }
    
    // 初始化队列
    lq->head = NULL;
    lq->tail = NULL;
    lq->clen = 0;
    
    return lq;
}

// 元素入队
int EnterLinkQue(LinkQue *lq, DATATYPE *newdata)
{
    // 创建新节点
    LinkQueNode *newnode = (LinkQueNode *)malloc(sizeof(LinkQueNode));
    if (NULL == newnode) {
        printf("EnterLinkQue malloc error\n");
        return 1;
    }
    
    // 复制数据到新节点
    memcpy(&newnode->data, newdata, sizeof(DATATYPE));
    newnode->next = NULL;
    
    // 如果队列为空,新节点同时是队头和队尾
    if (IsEmptyLinkQue(lq)) {
        lq->head = newnode;
        lq->tail = newnode;
    } else {
        // 否则添加到队尾
        lq->tail->next = newnode;
        lq->tail = newnode;
    }
    
    lq->clen++;  // 队列长度加1
    return 0;
}

// 元素出队
int QuitLinkQue(LinkQue *lq)
{
    if (IsEmptyLinkQue(lq)) {
        return 1;  // 队列为空,出队失败
    }
    
    LinkQueNode *tmp = lq->head;  // 保存队头节点
    lq->head = lq->head->next;    // 队头指向下一个节点
    
    // 如果队列变空,队尾也要置空
    if (NULL == lq->head) {
        lq->tail = NULL;
    }
    
    free(tmp);     // 释放原队头节点
    lq->clen--;    // 队列长度减1
    
    return 0;
}

// 获取队头元素(不删除)
DATATYPE *GetHeadLinkQue(LinkQue *lq)
{
    if (IsEmptyLinkQue(lq)) {
        return NULL;  // 队列为空,返回NULL
    }
    return &lq->head->data;  // 返回队头数据指针
}

// 获取队列当前大小
int GetSizeLinkQue(LinkQue *lq)
{
    return lq->clen;
}

// 检查队列是否为空
int IsEmptyLinkQue(LinkQue *lq)
{
    return 0 == lq->clen;
}

// 销毁队列
int DestroyLinkQue(LinkQue *lq)
{
    int size = GetSizeLinkQue(lq);
    int i = 0;
    
    // 循环出队所有元素
    for (i = 0; i < size; i++) {
        QuitLinkQue(lq);
    }
    
    free(lq);  // 释放队列结构体
    return 0;
}

4. 邮箱系统头文件 mailbox.h

cpp 复制代码
#ifndef _MAILBOX_H_
#define _MAILBOX_H_

#include <pthread.h>
#include "linkque.h"
#include "list.h"

// 线程函数指针类型
typedef void* (*th_fun)(void* arg);

// 线程节点结构
typedef struct thread_node {
    pthread_t tid;           // 线程ID
    char name[256];          // 线程名称(必须唯一)
    LinkQue* lq;             // 该线程对应的消息队列
    th_fun th;               // 线程函数
    struct list_head node;   // 链表节点
} LIST_DATA;

// 邮箱系统结构
typedef struct mail_box_system {
    pthread_mutex_t mutex;   // 保护邮件系统的互斥锁
    struct list_head head;   // 线程节点链表头
} MBS;

// ================== 邮箱系统接口 ==================

// 创建邮箱系统
MBS* create_mail_box_system();

// 销毁邮箱系统
void destroy_mail_box_system(MBS* mbs);

// 注册线程到邮箱系统
int register_to_mail_system(MBS* mbs, char name[], th_fun th);

// 等待所有线程结束
int wait_all_end(MBS* mbs);

// 发送消息
int send_msg(MBS* mbs, char* recvname, MAIL_DATA* data);

// 接收消息
int recv_msg(MBS* mbs, MAIL_DATA* data);

#endif /* _MAILBOX_H_ */

5. 邮箱系统实现 mailbox.c

cpp 复制代码
#include "mailbox.h"
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "linkque.h"

// 创建邮箱系统
MBS* create_mail_box_system()
{
    MBS* m_mbs = malloc(sizeof(MBS));
    if (NULL == m_mbs) {
        perror("create_mail_box_system malloc");
        return NULL;
    }
    
    // 初始化链表头和互斥锁
    INIT_LIST_HEAD(&m_mbs->head);
    pthread_mutex_init(&m_mbs->mutex, NULL);
    
    return m_mbs;
}

// 注册线程到邮箱系统
int register_to_mail_system(MBS* mbs, char name[], th_fun th)
{
    LIST_DATA* list_node = malloc(sizeof(LIST_DATA));
    if (NULL == list_node) {
        perror("register_to_mail_system malloc");
        return 1;
    }
    
    // 初始化线程节点
    strcpy(list_node->name, name);
    list_node->lq = CreateLinkQue();  // 为线程创建消息队列
    list_node->th = th;
    
    // 添加到链表
    list_add(&list_node->node, &mbs->head);
    
    // 创建线程
    pthread_create(&list_node->tid, NULL, th, NULL);
    
    return 0;
}

// 等待所有注册的线程结束
int wait_all_end(MBS* mbs)
{
    LIST_DATA *pos, *q;
    
    // 安全遍历所有线程节点
    list_for_each_entry_safe(pos, q, &mbs->head, node) {
        pthread_join(pos->tid, NULL);  // 等待线程结束
    }
    
    return 0;
}

// 通过名称查找线程节点
LIST_DATA* find_node_byname(MBS* mbs, char* name)
{
    LIST_DATA *pos, *q;
    
    // 遍历链表查找匹配名称的节点
    list_for_each_entry_safe(pos, q, &mbs->head, node) {
        if (0 == strcmp(pos->name, name)) {
            return pos;
        }
    }
    
    return NULL;
}

// 通过线程ID查找线程节点
LIST_DATA* find_node_byid(MBS* mbs, pthread_t id)
{
    LIST_DATA *pos, *q;
    
    // 遍历链表查找匹配ID的节点
    list_for_each_entry_safe(pos, q, &mbs->head, node) {
        if (pos->tid == id) {
            return pos;
        }
    }
    
    return NULL;
}

// 发送消息给指定名称的线程
int send_msg(MBS* mbs, char* recvname, MAIL_DATA* data)
{
    // 查找发送者自己的信息
    LIST_DATA* myself = find_node_byid(mbs, pthread_self());
    if (NULL == myself) {
        fprintf(stderr, "sendmsg error, find myself id\n");
        return 1;
    }
    
    // 填充发送者信息到消息中
    data->id_of_sender = pthread_self();
    strcpy(data->name_of_sender, myself->name);
    
    // 查找接收者
    LIST_DATA* recver = find_node_byname(mbs, recvname);
    if (NULL == recver) {
        fprintf(stderr, "sendmsg error, find recver name\n");
        return 1;
    }
    
    // 填充接收者信息到消息中
    data->id_of_recver = recver->tid;
    strcpy(data->name_of_recver, recver->name);
    
    // 加锁保护队列操作
    pthread_mutex_lock(&mbs->mutex);
    EnterLinkQue(recver->lq, data);  // 消息入队
    pthread_mutex_unlock(&mbs->mutex);
    
    return 0;
}

// 接收消息(从自己的消息队列)
int recv_msg(MBS* mbs, MAIL_DATA* data)
{
    // 查找自己的线程节点
    LIST_DATA* myself = find_node_byid(mbs, pthread_self());
    if (NULL == myself) {
        fprintf(stderr, "recv_msg find_node_byid myself\n");
        return 0;
    }
    
    // 加锁保护队列操作
    pthread_mutex_lock(&mbs->mutex);
    
    // 获取队头消息
    MAIL_DATA* tmp = GetHeadLinkQue(myself->lq);
    if (NULL == tmp) {
        pthread_mutex_unlock(&mbs->mutex);
        return 1;  // 队列为空
    }
    
    // 复制消息数据
    memcpy(data, tmp, sizeof(MAIL_DATA));
    QuitLinkQue(myself->lq);  // 消息出队
    
    pthread_mutex_unlock(&mbs->mutex);
    
    return 0;
}

// 销毁邮箱系统
void destroy_mail_box_system(MBS* mbs)
{
    LIST_DATA *pos, *q;
    
    // 安全遍历并释放所有线程节点
    list_for_each_entry_safe(pos, q, &mbs->head, node) {
        list_del(&pos->node);        // 从链表删除
        DestroyLinkQue(pos->lq);     // 销毁消息队列
        free(pos);                   // 释放节点内存
    }
    
    pthread_mutex_destroy(&mbs->mutex);  // 销毁互斥锁
    free(mbs);                          // 释放邮箱系统内存
    
    return;
}

6. 主程序示例 main.c

cpp 复制代码
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "linkque.h"
#include "list.h"
#include "mailbox.h"

// 全局邮箱系统指针
MBS* g_mbs;

// 显示线程函数 - 接收并显示温度数据
void* show_th(void* arg)
{
    MAIL_DATA data;
    
    while (1) {
        bzero(&data, sizeof(MAIL_DATA));  // 清空数据缓冲区
        
        // 尝试接收消息
        int ret = recv_msg(g_mbs, &data);
        if (1 == ret) {
            sleep(1);  // 没有消息,休眠1秒
            continue;
        }
        
        // 显示接收到的消息
        printf("show_th sendname[%s]: %s\n", data.name_of_sender, data.data);
    }
    
    return NULL;
}

// socket线程函数 - 接收并显示温度数据(模拟网络发送)
void* sock_th(void* arg)
{
    MAIL_DATA data;
    
    while (1) {
        bzero(&data, sizeof(MAIL_DATA));  // 清空数据缓冲区
        
        // 尝试接收消息
        int ret = recv_msg(g_mbs, &data);
        if (1 == ret) {
            sleep(1);  // 没有消息,休眠1秒
            continue;
        }
        
        // 显示接收到的消息
        printf("sock_th sendname[%s]: %s\n", data.name_of_sender, data.data);
    }
    
    return NULL;
}

// 数据生成线程函数 - 生成随机温度数据并发送
void* data_th(void* arg)
{
    srand(time(NULL));  // 初始化随机数种子
    MAIL_DATA data;
    
    while (1) {
        // 生成30.00-50.00之间的随机温度
        int num = rand() % 2000 + 3000;  // 3000-4999
        float tmp = num / 100.0;         // 30.00-49.99
        
        bzero(&data, sizeof(data));  // 清空数据缓冲区
        
        // 格式化温度数据
        sprintf(data.data, "Temperature: %.2f°C", tmp);
        
        // 发送给显示线程
        send_msg(g_mbs, "show", &data);
        sleep(rand() % 3);  // 随机休眠0-2秒
        
        // 发送给socket线程
        send_msg(g_mbs, "sock", &data);
        sleep(rand() % 2);  // 随机休眠0-1秒
    }
    
    return NULL;
}

// 主函数
int main(int argc, char** argv)
{
    // 1. 创建邮箱系统
    g_mbs = create_mail_box_system();
    if (NULL == g_mbs) {
        fprintf(stderr, "Failed to create mail box system\n");
        return 1;
    }
    
    printf("Mailbox system created successfully!\n");
    
    // 2. 注册三个工作线程
    printf("Registering threads...\n");
    register_to_mail_system(g_mbs, "show", show_th);  // 显示线程
    register_to_mail_system(g_mbs, "sock", sock_th);  // 网络线程
    register_to_mail_system(g_mbs, "data", data_th);  // 数据生成线程
    
    printf("All threads registered. Starting communication...\n");
    printf("==============================================\n");
    
    // 3. 等待所有线程结束(实际上线程不会主动结束,需要Ctrl+C终止)
    wait_all_end(g_mbs);
    
    // 4. 销毁邮箱系统(正常情况下不会执行到这里)
    destroy_mail_box_system(g_mbs);
    
    return 0;
}

三、编译与运行

1. 编译脚本 Makefile

cpp 复制代码
CC = gcc
CFLAGS = -Wall -g -pthread
TARGET = mailbox_system
OBJS = main.o linkque.o mailbox.o

all: $(TARGET)

$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $(TARGET) $(OBJS)

main.o: main.c mailbox.h linkque.h list.h
	$(CC) $(CFLAGS) -c main.c

linkque.o: linkque.c linkque.h
	$(CC) $(CFLAGS) -c linkque.c

mailbox.o: mailbox.c mailbox.h linkque.h list.h
	$(CC) $(CFLAGS) -c mailbox.c

clean:
	rm -f $(OBJS) $(TARGET)

run: $(TARGET)
	./$(TARGET)

2. 编译命令

复制代码
# 方法1:使用Makefile
make
make run

# 方法2:直接编译
gcc -o mailbox_system main.c linkque.c mailbox.c -lpthread

3. 运行输出示例

复制代码
Mailbox system created successfully!
Registering threads...
All threads registered. Starting communication...
==============================================
show_th sendname[data]: Temperature: 42.15°C
sock_th sendname[data]: Temperature: 42.15°C
show_th sendname[data]: Temperature: 36.78°C
sock_th sendname[data]: Temperature: 36.78°C
show_th sendname[data]: Temperature: 45.92°C
sock_th sendname[data]: Temperature: 45.92°C
...

四、系统设计与原理

1. 设计模式

生产者-消费者模式
  • 生产者 : data_th线程生成数据

  • 消费者 : show_thsock_th线程消费数据

  • 缓冲区: 消息队列作为缓冲区,解耦生产者和消费者

观察者模式
  • 一个数据源(生产者)可以通知多个观察者(消费者)

  • 观察者通过注册自己的消息队列来接收通知

2. 线程安全机制

复制代码
// 关键同步点
pthread_mutex_lock(&mbs->mutex);
// 临界区操作:队列入队/出队
pthread_mutex_unlock(&mbs->mutex);

3. 内存管理

  1. 创建时分配:

    • 邮箱系统结构体

    • 线程节点结构体

    • 消息队列结构体

    • 消息节点(入队时)

  2. 销毁时释放:

    • 逆序释放所有分配的内存

    • 防止内存泄漏

4. 消息传递流程

复制代码
1. data_th线程生成数据
2. 调用send_msg()发送给"show"和"sock"
3. send_msg()查找接收者队列
4. 消息入队到接收者队列
5. show_th/sock_th调用recv_msg()
6. recv_msg()从自己的队列出队
7. 处理接收到的消息

五、扩展与优化

1. 功能扩展建议

复制代码
// 1. 消息优先级
typedef struct mail_data {
    // ... 原有字段
    int priority;  // 消息优先级
    time_t timestamp;  // 发送时间戳
} MAIL_DATA;

// 2. 消息确认机制
typedef struct ack_data {
    pthread_t original_sender;
    char message_id[64];
    int status;  // 0=未确认, 1=已接收, 2=已处理
} ACK_DATA;

// 3. 广播消息
int broadcast_msg(MBS* mbs, MAIL_DATA* data) {
    LIST_DATA *pos, *q;
    list_for_each_entry_safe(pos, q, &mbs->head, node) {
        EnterLinkQue(pos->lq, data);
    }
    return 0;
}

2. 性能优化建议

  1. 锁粒度优化:

    复制代码
    // 细粒度锁:每个队列单独一把锁
    typedef struct thread_node {
        pthread_mutex_t queue_mutex;  // 队列专用锁
        // ... 其他字段
    } LIST_DATA;
  2. 内存池优化:

    复制代码
    // 预分配消息节点内存池
    #define POOL_SIZE 1000
    LinkQueNode *node_pool[POOL_SIZE];
  3. 无锁队列:

    • 使用原子操作实现无锁队列

    • 适用高并发场景

3. 错误处理增强

复制代码
// 添加错误码枚举
typedef enum {
    MB_SUCCESS = 0,
    MB_ERR_MALLOC,
    MB_ERR_QUEUE_FULL,
    MB_ERR_THREAD_NOT_FOUND,
    MB_ERR_TIMEOUT,
    // ... 其他错误码
} MB_ERROR_CODE;

// 增强的错误处理函数
MB_ERROR_CODE send_msg_ex(MBS* mbs, char* recvname, 
                          MAIL_DATA* data, int timeout_ms);

六、应用场景

1. 实时数据采集系统

  • 传感器数据采集线程 → 数据处理线程 → 显示/存储线程

2. 网络服务器

  • 接收线程 → 业务处理线程 → 发送线程

3. 事件驱动架构

  • 事件源 → 事件分发器 → 事件处理器

4. 插件系统

  • 主程序 → 插件管理器 → 各个插件

七、总结

这个邮箱系统实现具有以下特点:

优点:

  1. 模块化设计:链表、队列、邮箱系统分离,易于维护

  2. 线程安全:完善的锁机制保护共享资源

  3. 灵活扩展:基于Linux内核链表,易于添加新功能

  4. 异步通信:生产者消费者解耦,提高系统响应性

  5. 跨平台:基于POSIX线程,可移植性好

注意事项:

  1. 线程函数需要正确处理退出条件

  2. 消息队列可能积压,需要监控队列长度

  3. 线程名称必须唯一,否则消息路由会出错

  4. 需要考虑消息丢失和重复的处理

相关推荐
生活很暖很治愈9 小时前
Linux基础开发工具
linux·服务器·git·vim
打工的小王9 小时前
docker(三)具体项目的部署
运维·docker·容器
似霰10 小时前
Linux Shell 脚本编程——核心基础语法
linux·shell
A9better10 小时前
嵌入式开发学习日志50——任务调度与状态
stm32·嵌入式硬件·学习
非凡ghost11 小时前
ESET NupDown Tools 数据库下载工具
学习·软件需求
步步为营DotNet12 小时前
深度剖析.NET中IHostedService:后台服务管理的关键组件
服务器·网络·.net
一叶星殇12 小时前
.NET WebAPI:用 Nginx 还是 IIS 更好
运维·nginx·.net
zzcufo12 小时前
多邻国第5阶段17-18学习笔记
笔记·学习
LUCIFER12 小时前
[驱动进阶——MIPI摄像头驱动(五)]rk3588+OV13855摄像头驱动加载过程详细解析第四部分——ISP驱动
linux·驱动开发
Ares-Wang12 小时前
网络》》路由引入 、路由控制 》》路由策略 route-policy 、Filter-Policy(过滤策略)
网络·智能路由器