C++编程:实现类似 Windows SendMessage和 PostMessage的消息传递机制

0. 引言

本文实现一个简单的 Linux 消息传递机制,通过优先级队列、线程安全的消息队列和同步异步机制,模拟 Windows 中的 SendMessagePostMessage 功能。

SendMessagePostMessage 的主要区别在于:

  • SendMessage 是同步消息发送机制,调用线程会阻塞,直到目标线程处理完消息并返回结果。
  • PostMessage 是异步消息发送机制,消息会立即被放入消息队列,调用线程不会等待消息处理的完成。

1. 设计思路

实现 SendMessagePostMessage 的目标是让两个或多个线程能够通过消息传递进行通信,尤其是在一个线程中发送消息,另一个线程异步或同步地处理这些消息。设计要点:

  • 消息结构的定义:设计一个通用的消息结构,包含消息的类型、参数和返回值。消息类型区分同步消息(SendMessage)和异步消息(PostMessage)。

  • 消息队列的使用:通过一个线程安全的消息队列(MessageQueue)来存储和管理消息。消息队列的线程安全性可以通过使用互斥锁(std::mutex)和条件变量(std::condition_variable)来实现。

  • 同步与异步消息处理:通过 std::promisestd::future 实现同步消息的返回值,而异步消息则直接丢入队列,无需返回结果。

  • 优先级管理:为了确保同步消息的优先处理,我们可以使用 std::priority_queue 来存储消息,将同步消息的优先级设置为更高,从而确保 SendMessage 被优先处理。

  • 消息处理线程:独立的消息处理线程负责从队列中取出消息并进行处理。通过不断循环地从队列中取出消息,确保消息得到及时处理。

2. 完整代码

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <functional>
#include <future>
#include <memory>
#include <chrono>

// 定义消息类型
enum class MessageType {
    kSync,  // 同步消息(SendMessage)
    kAsync  // 异步消息(PostMessage)
};

// 消息结构体
struct Message {
    int msg_id;
    int w_param;
    int l_param;
    std::shared_ptr<std::promise<int>> promise_ptr;
    MessageType type;

    // 用于优先级队列排序,确保同步消息优先处理
    bool operator<(const Message& other) const {
        return type > other.type;  // 同步消息的优先级高
    }
};

// 消息队列类,线程安全
class MessageQueue {
public:
    // 添加消息到队列
    void Enqueue(const Message& msg) {
        std::lock_guard<std::mutex> lock(mtx_);
        queue_.push(msg);
        cv_.notify_one();  // 唤醒消息处理线程
    }

    // 从队列中取出消息
    Message Dequeue() {
        std::unique_lock<std::mutex> lock(mtx_);
        cv_.wait(lock, [this] { return !queue_.empty() || terminate_flag_; });

        if (terminate_flag_ && queue_.empty()) {
            return Message{};  // 返回默认消息,标识终止
        }

        Message msg = queue_.top();
        queue_.pop();
        return msg;
    }

    // 终止消息处理
    void Terminate() {
        std::lock_guard<std::mutex> lock(mtx_);
        terminate_flag_ = true;
        cv_.notify_all();  // 通知消息处理线程终止
    }

private:
    std::priority_queue<Message> queue_;
    std::mutex mtx_;
    std::condition_variable cv_;
    bool terminate_flag_ = false;  // 用于通知终止消息处理
};

// 全局消息队列
MessageQueue g_message_queue;

// 消息处理线程函数
void MessageHandler() {
    while (true) {
        Message msg = g_message_queue.Dequeue();
        if (msg.msg_id == 0 && !msg.promise_ptr) {
            break;  // 处理完终止消息,退出线程
        }

        // 处理消息(示例:简单输出消息ID及参数)
        std::cout << "Processing Message ID: " << msg.msg_id
                  << ", wParam: " << msg.w_param
                  << ", lParam: " << msg.l_param << std::endl;

        // 假设消息处理是返回 w_param + l_param 的结果
        int result = msg.w_param + msg.l_param;

        // 如果是同步消息,设置返回值
        if (msg.promise_ptr) {
            msg.promise_ptr->set_value(result);
        }
    }
}

// 启动消息处理线程
std::thread StartMessageLoop() {
    return std::thread(MessageHandler);
}

// SendMessage 实现(同步消息)
int SendMessage(int msg_id, int w_param, int l_param) {
    auto promise_ptr = std::make_shared<std::promise<int>>();
    std::future<int> fut = promise_ptr->get_future();

    Message msg;
    msg.msg_id = msg_id;
    msg.w_param = w_param;
    msg.l_param = l_param;
    msg.promise_ptr = promise_ptr;
    msg.type = MessageType::kSync;  // 设置为同步消息

    g_message_queue.Enqueue(msg);

    // 等待消息处理完成,并获取返回值
    return fut.get();
}

// PostMessage 实现(异步消息)
void PostMessage(int msg_id, int w_param, int l_param) {
    Message msg;
    msg.msg_id = msg_id;
    msg.w_param = w_param;
    msg.l_param = l_param;
    msg.promise_ptr = nullptr;  // 异步消息不需要返回值
    msg.type = MessageType::kAsync;  // 设置为异步消息

    g_message_queue.Enqueue(msg);
}

// 示例使用
int main() {
    // 启动消息处理线程
    std::thread msg_thread = StartMessageLoop();

    // 发送一个同步消息
    std::cout << "Sending synchronous message..." << std::endl;
    int send_result = SendMessage(1, 10, 20);
    std::cout << "SendMessage result: " << send_result << std::endl;

    // 发送一个异步消息
    std::cout << "Posting asynchronous message..." << std::endl;
    PostMessage(2, 30, 40);

    // 给异步消息一些处理时间
    std::this_thread::sleep_for(std::chrono::seconds(1));

    // 终止消息处理线程
    g_message_queue.Terminate();
    msg_thread.join();

    return 0;
}

3. 关键设计细节

3.1. 消息结构 (Message)

在消息传递机制中,首先需要定义消息的结构体。该结构体包含消息的 ID(msg_id)、附加的参数(w_paraml_param)、同步返回值的 promise_ptr(针对 SendMessage)以及消息类型(MessageType)。

enum class MessageType {
    kSync,  // 同步消息(SendMessage)
    kAsync  // 异步消息(PostMessage)
};

struct Message {
    int msg_id;
    int w_param;
    int l_param;
    std::shared_ptr<std::promise<int>> promise_ptr;
    MessageType type;

    bool operator<(const Message& other) const {
        return type > other.type;  // 同步消息优先
    }
};

在该结构体中:

  • msg_id 用于标识消息类型;
  • w_paraml_param 是附加的参数,用于传递消息相关的数据;
  • promise_ptr 是一个指向 std::promise<int> 的智能指针,SendMessage 通过它返回处理结果;
  • type 用于标识消息类型,分为同步 (kSync) 和异步 (kAsync) 消息。

通过重载 < 运算符,我们可以确保同步消息(kSync)在消息队列中具有较高的优先级,从而优先处理。

3.2. 消息队列 (MessageQueue)

为了存储消息并确保线程安全,我们需要一个线程安全的队列。在这里我们使用 std::priority_queue 来存储消息。通过互斥锁 (std::mutex) 来保证队列的线程安全,并使用条件变量 (std::condition_variable) 实现线程的阻塞和唤醒。

class MessageQueue {
public:
    void Enqueue(const Message& msg) {
        std::lock_guard<std::mutex> lock(mtx_);
        queue_.push(msg);
        cv_.notify_one();  // 唤醒消息处理线程
    }

    Message Dequeue() {
        std::unique_lock<std::mutex> lock(mtx_);
        cv_.wait(lock, [this] { return !queue_.empty() || terminate_flag_; });
        if (terminate_flag_ && queue_.empty()) {
            return Message{};  // 终止信号
        }

        Message msg = queue_.top();
        queue_.pop();
        return msg;
    }

    void Terminate() {
        std::lock_guard<std::mutex> lock(mtx_);
        terminate_flag_ = true;
        cv_.notify_all();  // 唤醒消息处理线程
    }

private:
    std::priority_queue<Message> queue_;
    std::mutex mtx_;
    std::condition_variable cv_;
    bool terminate_flag_ = false;
};

在这个类中:

  • Enqueue 方法用于将消息添加到队列中,并唤醒等待的线程;
  • Dequeue 方法用于从队列中获取消息,如果队列为空,则等待;
  • Terminate 方法用于发送一个终止信号,通知消息处理线程退出。

3.3. 同步与异步消息

我们通过 std::promisestd::future 来实现同步消息的返回值,确保调用者能够获得处理结果。而对于异步消息,消息的发送线程不需要等待处理结果,直接将消息丢入队列即可。

// 同步消息(SendMessage)
int SendMessage(int msg_id, int w_param, int l_param) {
    auto promise_ptr = std::make_shared<std::promise<int>>();
    std::future<int> fut = promise_ptr->get_future();

    Message msg;
    msg.msg_id = msg_id;
    msg.w_param = w_param;
    msg.l_param = l_param;
    msg.promise_ptr = promise_ptr;
    msg.type = MessageType::kSync;  // 同步消息

    g_message_queue.Enqueue(msg);

    // 等待处理结果并返回
    return fut.get();
}

// 异步消息(PostMessage)
void PostMessage(int msg_id, int w_param, int l_param) {
    Message msg;
    msg.msg_id = msg_id;
    msg.w_param = w_param;
    msg.l_param = l_param;
    msg.promise_ptr = nullptr;  // 异步消息不需要返回值
    msg.type = MessageType::kAsync;  // 异步消息

    g_message_queue.Enqueue(msg);
}

SendMessage 通过 std::promisestd::future 实现同步消息的等待和返回,而 PostMessage 则是简单地将消息放入队列,不需要等待结果。

3.4. 消息处理线程

消息处理线程负责从队列中取出消息并进行处理。在处理完消息后,如果是同步消息,设置返回值。

void MessageHandler() {
    while (true) {
        Message msg = g_message_queue.Dequeue();
        if (msg.msg_id == 0 && !msg.promise_ptr) {
            break;  // 处理完终止消息,退出线程
        }

        // 处理消息
        int result = msg.w_param + msg.l_param;  // 示例处理逻辑

        // 设置返回值(如果是同步消息)
        if (msg.promise_ptr) {
            msg.promise_ptr->set_value(result);
        }
    }
}

该线程不断从消息队列中取出消息并处理,示例中我们简单地返回 w_param + l_param 作为处理结果。如果是同步消息,处理结果会通过 std::promise 返回给调用者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘色的喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值