用 C 实现一个简化版 MessageQueue

Android 的 MessageQueue 很复杂(native poll/epoll、barrier、idle handler...)

但它的核心思想非常简单

✅ 一个队列存消息

✅ 一个循环不断取消息执行

✅ 线程安全(加锁/条件变量)

我们用 C 写一个可跑的简化版

  • 支持 post(msg)

  • 支持 loop() 阻塞取消息

  • 支持 quit() 退出

1)数据结构:消息节点 + 队列

cpp 复制代码
typedef struct Message {
    int what;
    void (*callback)(int what); // 收到消息后执行的回调
    struct Message* next;
} Message;

typedef struct {
    Message* head;
    Message* tail;
    int quit;
    pthread_mutex_t mutex;
    pthread_cond_t  cond;
} MessageQueue;

2)队列初始化 / 销毁

cpp 复制代码
void mq_init(MessageQueue* q){
    q->head = q->tail = NULL;
    q->quit = 0;
    pthread_mutex_init(&q->mutex, NULL);
    pthread_cond_init(&q->cond, NULL);
}

void mq_destroy(MessageQueue* q){
    pthread_mutex_lock(&q->mutex);
    Message* cur = q->head;
    while(cur){
        Message* next = cur->next;
        free(cur);
        cur = next;
    }
    q->head = q->tail = NULL;
    pthread_mutex_unlock(&q->mutex);

    pthread_mutex_destroy(&q->mutex);
    pthread_cond_destroy(&q->cond);
}

3)post:入队 + 唤醒 loop

cpp 复制代码
void mq_post(MessageQueue* q, int what, void (*cb)(int)){
    Message* m = (Message*)malloc(sizeof(Message));
    m->what = what;
    m->callback = cb;
    m->next = NULL;

    pthread_mutex_lock(&q->mutex);

    if(q->tail == NULL){
        q->head = q->tail = m;
    }else{
        q->tail->next = m;
        q->tail = m;
    }

    pthread_cond_signal(&q->cond); // 通知消费者
    pthread_mutex_unlock(&q->mutex);
}

4)next:阻塞取消息(队列空就等)

cpp 复制代码
Message* mq_next(MessageQueue* q){
    pthread_mutex_lock(&q->mutex);

    while(!q->quit && q->head == NULL){
        pthread_cond_wait(&q->cond, &q->mutex);
    }

    if(q->quit){
        pthread_mutex_unlock(&q->mutex);
        return NULL;
    }

    Message* m = q->head;
    q->head = m->next;
    if(q->head == NULL) q->tail = NULL;

    pthread_mutex_unlock(&q->mutex);
    return m;
}

5)loop:像 Looper 一样执行消息

cpp 复制代码
void mq_loop(MessageQueue* q){
    while(1){
        Message* m = mq_next(q);
        if(m == NULL) break;

        if(m->callback){
            m->callback(m->what);
        }
        free(m);
    }
}

6)quit:让 loop 退出

cpp 复制代码
void mq_quit(MessageQueue* q){
    pthread_mutex_lock(&q->mutex);
    q->quit = 1;
    pthread_cond_broadcast(&q->cond);
    pthread_mutex_unlock(&q->mutex);
}

7)完整可运行 Demo(Linux / macOS)

编译:gcc mq.c -o mq -lpthread

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

typedef struct Message {
    int what;
    void (*callback)(int what);
    struct Message* next;
} Message;

typedef struct {
    Message* head;
    Message* tail;
    int quit;
    pthread_mutex_t mutex;
    pthread_cond_t  cond;
} MessageQueue;

void mq_init(MessageQueue* q){
    q->head = q->tail = NULL;
    q->quit = 0;
    pthread_mutex_init(&q->mutex, NULL);
    pthread_cond_init(&q->cond, NULL);
}

void mq_post(MessageQueue* q, int what, void (*cb)(int)){
    Message* m = (Message*)malloc(sizeof(Message));
    m->what = what;
    m->callback = cb;
    m->next = NULL;

    pthread_mutex_lock(&q->mutex);
    if(q->tail == NULL){
        q->head = q->tail = m;
    }else{
        q->tail->next = m;
        q->tail = m;
    }
    pthread_cond_signal(&q->cond);
    pthread_mutex_unlock(&q->mutex);
}

Message* mq_next(MessageQueue* q){
    pthread_mutex_lock(&q->mutex);
    while(!q->quit && q->head == NULL){
        pthread_cond_wait(&q->cond, &q->mutex);
    }
    if(q->quit){
        pthread_mutex_unlock(&q->mutex);
        return NULL;
    }
    Message* m = q->head;
    q->head = m->next;
    if(q->head == NULL) q->tail = NULL;
    pthread_mutex_unlock(&q->mutex);
    return m;
}

void mq_quit(MessageQueue* q){
    pthread_mutex_lock(&q->mutex);
    q->quit = 1;
    pthread_cond_broadcast(&q->cond);
    pthread_mutex_unlock(&q->mutex);
}

void mq_loop(MessageQueue* q){
    while(1){
        Message* m = mq_next(q);
        if(m == NULL) break;
        if(m->callback) m->callback(m->what);
        free(m);
    }
}

void mq_destroy(MessageQueue* q){
    pthread_mutex_lock(&q->mutex);
    Message* cur = q->head;
    while(cur){
        Message* next = cur->next;
        free(cur);
        cur = next;
    }
    q->head = q->tail = NULL;
    pthread_mutex_unlock(&q->mutex);

    pthread_mutex_destroy(&q->mutex);
    pthread_cond_destroy(&q->cond);
}

void on_msg(int what){
    printf("handle msg what=%d (thread=%lu)\n", what, (unsigned long)pthread_self());
}

typedef struct {
    MessageQueue* q;
} ProducerArg;

void* producer(void* arg){
    ProducerArg* pa = (ProducerArg*)arg;
    for(int i=1;i<=5;i++){
        mq_post(pa->q, i, on_msg);
        usleep(200 * 1000);
    }
    mq_quit(pa->q);
    return NULL;
}

int main(){
    MessageQueue q;
    mq_init(&q);

    pthread_t t;
    ProducerArg pa = { .q = &q };
    pthread_create(&t, NULL, producer, &pa);

    mq_loop(&q);

    pthread_join(t, NULL);
    mq_destroy(&q);
    return 0;
}

8)这跟 Android MessageQueue 的对应关系

  • mq_postenqueueMessage
  • mq_nextnext()
  • mq_loopLooper.loop()
  • cond_wait ≈ "没有消息就阻塞等待"
  • quitLooper.quit()
相关推荐
郑州光合科技余经理8 小时前
本地生活系统:多业务订单字段怎么分账本导出
java·开发语言·前端·数据库·uni-app·php·ai编程
weixin199701080168 小时前
《跨境二手ERP的3种对接模式:自研API / SaaS中间件 / 平台认证服务商,怎么选?》(附Python源码)
开发语言·python·中间件
传奇开心果编程11 小时前
【Rust入门知识点学与练】第24课:Trait 基础
开发语言·学习·rust
wuminyu14 小时前
Kafka中sendfile与mmap实现机制解析
java·linux·c语言·jvm·c++
Blockbuater_drug15 小时前
FreeSASA: 开源 SASA 计算库,pip 一条命令替代 NACCESS
c语言·开源·sasa·freesasa·溶剂可及表面积·naccess·python api
Logic10116 小时前
C语言/数据结构位运算题解:异或XOR找出蛋糕订单中的“VIP独特口味“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
言乐616 小时前
Python加速器4跨境网络加速器
运维·服务器·开发语言·网络·python
金金计较.16 小时前
Go语言-3
java·开发语言·golang
Logic10117 小时前
C语言/数据结构位运算题解:异或XOR找出飞行棋中的“独特颜色棋子“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
张小凡vip17 小时前
python--爬虫--经验积累的遇到的坑
开发语言·爬虫·python