可以像这样使用PostMessage()吗?

huangapple go评论76阅读模式
英文:

Can I use PostMessage() like this?

问题

Here is the modified code with comments translated into Chinese:

UINT ThreadFunc(LPVOID pParam) {
    pointerToMainUI->PostMessage(WM_EXAMPLE, MSG_EXAMPLE_1, 1);    
    pointerToMainUI->PostMessage(WM_EXAMPLE, MSG_EXAMPLE_2, 2); // 问题 1
}

void MyDialogExClass::OnBnClickedStart() {
    int intA = 0; // 声明为公共全局变量

    mThreadA = AfxBeginThread(ThreadFunc, this);
    mThreadB = AfxBeginThread(ThreadFunc, this); // 问题 2
}

LRESULT MyDialogExClass::WinProc(WPARAM wParam, LPARAM lParam) {
    
    int iParam = (int)lParam;

    switch (wParam) {
    case MSG_EXAMPLE_1:
        intA = iParam;
        break;

    case MSG_EXAMPLE_2:
        // 执行某些操作
        break;
    }
    
    return LRESULT();
}

请注意,这是您提供的代码的翻译版本。如果您有任何其他问题或需要进一步的修改,请随时提出。

英文:

I am currently working on an MFC project, which runs several threads and uses PostMessage() for the message exchange between the worker thread and the Main UI thread.

I wrote a code like below:

UINT ThreadFunc (LPVOID pParam) {
    pointerToMainUI->PostMessage(WM_EXAMPLE, MSG_EXAMPLE_1, 1);    
    pointerToMainUI->PostMessage(WM_EXAMPLE, MSG_EXAMPLE_2, 2); // Question 1
}

void MyDialogExClass::OnBnClickedStart() {
    int intA = 0; // Declared in header as public global

    mThreadA = AfxBeginThread(ThreadFunc , this);
    mThreadB = AfxBeginThread(ThreadFunc , this); // Question 2
}

LRESULT MyDialogExClass::WinProc (WPARAM wParam, LPARAM lParam) {
    
    int iParam = (int)lParam;

    switch (wParam) {
    case MSG_EXAMPLE_1:
        intA = iParam;
        break;

    case MSG_EXAMPLE_2:
        // Do Something
        break;
    }
    
    return LRESULT();
}

It is important for my application to do FIFO, which had me wonder if my data and memory is at any risk.

My Question:

  1. Is it safe for me to have the thread do two PostMessage() calls in a row?

  2. Is it safe for me to have two different threads running that will change the value of a variable from the main thread?

答案1

得分: 2

  1. 在这种情况下,是的。您发布的值完全包含在消息的“lParam”中,因此没有跨线程问题可供发布。如果您正在发布值的指针,那就是另一回事。

  2. 在这种情况下,是的。您没有直接在您的线程中更新变量,而是将值委托给主UI线程,然后它会更新变量。消息将逐一处理,消息队列将确保它们按发布的顺序处理。

英文:
  1. In this case, yes. Your posted values are fully contained inside the lParam of the messages, so there is no cross-threading issue to post them. If you were posting pointers to values, that would be a different story.

  2. In this case, yes. You are not updating the variable directly in your threads, you are delegating the values to the main UI thread, and then it is updating the variable. The messages will be processed one at a time, and the message queue will ensure they are processed in the order that they are posted.

答案2

得分: 0

Here's the code with the requested translation:

是的,你现在正在做的事情是可以的,除了使用全局变量来更新。
以下是一个使用 std::thread  [lambda 函数](https://learn.microsoft.com/en-us/cpp/cpp/lambda-expressions-in-cpp?view=msvc-170) 的示例:

void MyDialogExClass::~MyDialogExClass()
{
    // 确保在对话框完全析构之前完成线程,否则可能会出现竞争条件。
    m_ThreadA.join();
    m_ThreadB.join();
}

void MyDialogExClass::OnBnClickedStart()
{
    // 待办事项:添加一些线程安全的逻辑,以避免在线程仍在运行时点击运行

    // 避免使用全局变量!
    // int intA = 0; // 在头文件中声明为公共全局变量

    // 不要使用 winapi 来启动线程
    // 传递数据给回调函数非常繁琐。
    // mThreadA = AfxBeginThread(ThreadFunc, this);
    // mThreadB = AfxBeginThread(ThreadFunc, this); // 问题 2

    // 使用 lambda 表达式调用成员函数,或使用成员变量的函数
    // [&] 将通过引用捕获 `this`
    // 线程将成为对话框的成员(您也可以使用 std::async 和 std::future)
    // std::thread m_ThreadA;
    // std::thread m_ThreadB;
    mThreadA = std::thread([&] { PostMessage(WM_EXMPLE, MSG_EAMPLE_1, 1); });
    mThreadB = std::thread([&] { PostMessage(WM_EXMPLE, MSG_EAMPLE_1, 1); });
}

LRESULT MyDialogExClass::WinProc(WPARAM wParam, LPARAM lParam) {

    int iParam = (int)lParam;

    switch (wParam) {
    case MSG_EXAMPLE_1:
        // intA = iParam; 不要使用全局变量(尤其不要在多线程环境中使用)
        break;

    case MSG_EXAMPLE_2:
        // 做一些事情
        break;
    }

    return LRESULT{};
}

请注意,代码中的注释已被翻译成中文。

英文:

Yes what you are doing is ok, except updating using global variables.
Here is an example using std::thread and lambda functions

void MyDialogExClass::~MyDialogExClass()
{
    // ensure threads are finished before Dialog is fully destructed.
    // or you might have a race condition.
    m_ThreadA.join();
    m_ThreadB.join();
}

void MyDialogExClass::OnBnClickedStart() 
{
    // Todo : Add some threadsafe logic to avoid click from running while
    // threads are still busy

    // avoid globals!
    // int intA = 0; // Declared in header as public global

    // Do NOT use winapi to start threads
    // it is really cumbersome to pass data to callbacks etc.
    // mThreadA = AfxBeginThread(ThreadFunc, this);
    // mThreadB = AfxBeginThread(ThreadFunc, this); // Question 2

    // use lambda expression to call member functions, or functions using member variables
    // [&] will capture `this` by reference
    // threads will be members of the dialog (you can also use std::async and std::future)
    // std::thread m_ThreadA;
    // std::thread m_ThreadB; 
    mThreadA = std::thread([&] { PostMessage(WM_EXMPLE, MSG_EAMPLE_1, 1); } );
    mThreadB = std::thread([&] { PostMessage(WM_EXMPLE, MSG_EAMPLE_1, 1); });
}

LRESULT MyDialogExClass::WinProc(WPARAM wParam, LPARAM lParam) {

    int iParam = (int)lParam;

    switch (wParam) {
    case MSG_EXAMPLE_1:
        // intA = iParam; Do NOT use globals (specialy not in multithreaded env)
        break;

    case MSG_EXAMPLE_2:
        // Do Something
        break;
    }

    return LRESULT{};
}

huangapple
  • 本文由 发表于 2023年7月17日 14:15:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76701897.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定