用 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()
相关推荐
小鹿学程序5 小时前
jdk配置完之后java -version还是默认的jdk版本如何更改
java·开发语言·python
至善迎风5 小时前
Bun:下一代 JavaScript 运行时与工具链
开发语言·javascript·ecmascript·bun
程序员-King.5 小时前
【Qt开源项目】— ModbusScope-day 5
开发语言·qt
老秦包你会5 小时前
QT第五课------QT系统相关------线程
开发语言·qt
lkbhua莱克瓦245 小时前
IO练习——网络爬虫(爬取数据)
java·开发语言·爬虫·io流练习·java练习
net3m335 小时前
雅特力单片机用串口USART_INT_TDE中断比用USART_INT_TRAC的 发送效率要高
java·开发语言·算法
爱打代码的小林6 小时前
python基础(逻辑回归例题)
开发语言·python·逻辑回归
一过菜只因6 小时前
JavaWeb后端(spring--boot)
java·开发语言
五仁火烧6 小时前
安装rust开发环境
开发语言·后端·rust