改进线程同步机制 [英] Improve thread synchronisation mechanism

查看:67
本文介绍了改进线程同步机制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

介绍及相关信息:



我有一个带按钮的主窗口。



点击按钮,会出现一个对话框。



对话框有一个生成线程的按钮。 />


线程功能通过2 自定义消息与对话框通信。



现在我使用 boolean 变量,就像在编程Windows,第5版-Charles Petzold的线程示例中使用它一样。



我希望改进线程同步的代码,即替换 boolean的用法全局变量可以提高效率。



重要信息也是用户按下时线程中止的方式对话框或主窗口上的 Alt + F4 X按钮,以下是我已部署的算法的说明:



如果用户在线程仍在运行时尝试关闭主窗口,我设置全局布尔变量并保留 WM_CLOSE 处理程序而不破坏窗口。我还将 WM_CLOSE 发送到对话框。



在对话框程序中,在中WM_CLOSE 处理程序,我检查线程是否仍在运行,如果是,我发送中止信号并返回而不破坏对话框。



现在主窗口和对话框都处于活动状态并等待线程完成。



一旦线程发送自定义消息,通知它已完成的对话框,我检查全局布尔变量,如果设置了,我发布 WM_CLOSE 到主窗口,如果用户要求关闭它,我会将 WM_CLOSE 发布到对话框。



关闭请求for对话框存储在 boolean 变量中,该变量在用户尝试关闭对话框时设置。



As就线程函数而言,我会定期检查 bContinue 的值,并在设置为 false 时正确中止线程。


以下是相关的代码片段:

INTRODUCTION AND RELEVANT INFORMATION:

I have a main window with a button.

On button click a dialog box is shown.

Dialog box has a button that spawns a thread.

Thread function communicates with the dialog box via 2 custom messages.

Right now I am using a boolean variable the way it was used in the thread example from book Programming Windows, 5th edition-Charles Petzold.

I wish to improve the code for thread synchronization, namely to substitute the usage of boolean and global variables for something more efficient.

The important information is also the way threads are aborted when user presses Alt+F4 or X button on either dialog box or main window so here is the explanation of the algorithm I have deployed:

If the user tries to close the main window while thread is still running, I set the global boolean variable and leave WM_CLOSE handler without destroying the window. I also send WM_CLOSE to the dialog box.

In the dialog procedure, in WM_CLOSE handler, I check if thread is still running and if it does I send abort signal and return without destroying the dialog box.

Now both main window and dialog box are alive and wait for thread to finish.

Once thread sends custom message, informing the dialog box it has finished, I check the global boolean variable and if it is set I post the WM_CLOSE to the main window and I post WM_CLOSE to the dialog box if the user requested to close it.

Close request for dialog box is stored in a boolean variable that gets set when user tries to close dialog box.

As far as thread function is concerned, I check the value of bContinue periodically and abort thread properly when it is set to false.

Here are the relevant code snippets:

//GLOBAL VARIABLES:

struct Data
{ 
    bool bContinue; // continue thread execution?
    // other data
};

//global variable that indicates the main window's close request
static bool g_closeApp; 



主窗口的WM_CLOSE处理程序:


The main window's WM_CLOSE handler:

case WM_CLOSE:
    closeApp = true;
    /******* close dialogs ****/
    if( IsWindow( hDlgTSO ) )
    {
        SendMessage( hDlgTSO, WM_CLOSE, 0, 0 );
        return (LRESULT)0; //<-------return and wait for thread to finish
    }
    // perform usual cleanup and destroy window
    return (LRESULT)0;



相关对话框摘要:


The relevant dialog box snippets:

INT_PTR CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
    static HANDLE threadHandle;
    static Data data; //data sent to the thread function
    static bool closeDlg; // close dialog requested?

    switch(Message)
    {
    case WM_INITDIALOG:
        {
            closeDlg = false;
            threadHandle = NULL;
            // other stuff...
        }
        return TRUE;

    case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
            case IDOK:
                {
                     // create thred
                     DWORD threadID;
                     // initialize thread data
                     data.bContinue = true;

                     threadHandle = CreateThread( NULL, 0,
                                       (LPTHREAD_START_ROUTINE)ThreadFunction,
                                       (void*)&data, 0, &threadID );

                     if( !threadHandle )
                     {
                         MessageBox( hwnd, L"Error!", L"Error", MB_ICONERROR );
                         DestroyWindow(hwnd); // destroy modeless dialog box
                     }

                 }
                 break;
        }
        break;

    case WM_CLOSE:
        closeDlg = true; // user wants to close dialog
        if( threadHandle ) //if thread is running signal abort and wait
        {
            ShowWindow( hwnd, SW_HIDE );
            data.bContinue = false; 
        }
        else
        {
            if( closeApp ) // close main window?
                PostMessage( GetParent( hwnd ), WM_CLOSE, 0, 0 );

            threadHandle = NULL;
            DestroyWindow(hwnd);
            hDlgTSO = NULL; // needed-this is modeless dialog!
        }
        return TRUE;

    case WM_THREAD_OK: //custom message, indicates successful thread execution 
        if( threadHandle ) // wait for thread to fully exit
        {       
            WaitForSingleObject( threadHandle, INFINITE );
            CloseHandle( threadHandle );
            threadHandle = NULL;
        }

        // if in the meantime user pressed X or Alt+F4 post WM_CLOSE
        if( closeDlg )
            PostMessage( hwnd, WM_CLOSE, 0, 0 );
        return TRUE;

    default:
        return FALSE;
    }
    return TRUE;
}



线程函数:


The thread function:

DWORD WINAPI ThreadFunction( LPVOID pvoid )
{
    volatile Data* data = ( Data* )pvoid;
    //do something with data..
    if( ! data.bContinue ) // abort signal is set
    //do cleanup and return
}



我的问题:



是否有更好的实施方案可以让我删除布尔变量,尤其是全局变量



我不寻求建议对于同步机制,因为我相信当前的一个是好的,但如果有人有更好的建议我会考虑它。



谢谢。



祝你好运。


MY QUESTION:

Is there a better implementation which would enable me to remove boolean variables, especially the global one?

I do not seek suggestion for synchronization mechanism as I believe that current one is OK, but if anyone has better suggestion I will consider it.

Thank you.

Best regards.

推荐答案

当然,这种实现效率低,因为所有这些技术都基于轮询。首先,一方面注意:使用 struct Data 完全没有意义,因为它等同于使用 static bContinue 。此外,使用任何全局变量通常都很糟糕,您可以尝试使用线程本地存储。然而,所有这些都无助于解决更大的问题。



所有这些东西都减少到了一个非常严重的问题:一个线程可以以一种完全异步的方式终止线程代码的执行。实际上,答案是是,因为你总是可以使用非优雅的 TerminateThread 请,永远不要这样做!)。因此,更重要的问题是:线程是否可以完全异步地终止于安全中线程代码的执行?这个问题仍然存在问题。



首先,我将提出一个非常强大,有争议和不寻常的声明:大多数操作系统的开发人员都没有了解应用程序强加的要求。通常建议的做法是:使用合作方法。它意味着:你刚才使用的方法。操作系统开发人员没有意识到应用程序中这种方法完全不合适;我可以举几个例子。想象一下,您正在启动一个没有明确周期结构的复杂计算任务。尝试使用一些解微分方程组的数值方法,你就会理解我的意思。执行某些周期所需的时间跨度根本无法预测。此外,你不能把开发人员从重要的数值方法问题分散到愚蠢的线程合作,这是完全不相关的。还有许多其他例子,你真的需要中止一个线程。怎么安全地做?问题确实是一个大问题,而这仅仅是因为操作系统开发人员没有充分意识到问题的重要性。如果解决应用程序问题确实需要某些东西,应用程序开发人员将使用非优雅的方法,因此禁止异步终止会使事情变得更糟。



我发现了几年前真正的解决方案,不幸的是失去了对原创作品的参考。但我可以详细描述它。请参阅我以前的回答:正确关闭dll中的线程 [ ^ ]。



关于先发制人的概念,请阅读: http://en.wikipedia.org/wiki/Preemption_%28computing%29 [ ^ ]。



最后一个注释。上述解决方案省钱且高效,但在Windows API中从未被接受。然而,它进入了更加明智的API,即.NET。这就是.NET FCL Thread.Abort 的工作方式。



这个问题非常复杂且非平凡,所以非常欢迎你的后续问题。



-SA
Well, of course this implementation is inefficient as all those techniques based on polling. First, one side note: your use of struct Data is totally pointless, because it is equivalent to using static bContinue along. Also, using any global variables is generally bad, you could try to use, say, thread-local storage. However, all that would not help to solve the bigger problem.

All that stuff is reduced to really serious problem: can a thread be terminated in a way totally asynchronously to the execution of the thread code. Actually, the answer would be "yes", because you could always use non-graceful TerminateThread (please, never do it!). So, more essential question would be: can a thread be terminated in a way totally asynchronously to the execution of the thread code in safely? And this problem remains a problem.

To start with, I'm going to make a very strong, controversial and unusual statement: the developers of most operating systems did not understand the requirements imposed by the application. The usually recommended practice is: use cooperative approach. It means: the approach you just used. The OS developers did not realize that there are applications where such approach it totally unsuitable; and I can give you a number of examples. Imagine you are launching a complex calculation task which does not have distinct periodic structure. Try to use some numeric methods of solution of the system of differential equations and you will understand what I mean. The time spans needed for execution of certain cycles are simply unpredictable. Besides, you cannot distract the developer from important numerical-method problem to stupid thread cooperation, which is totally unrelated. There are many other examples where you really need to abort a thread. How to do it safely? The question is really a big problem, and this is so just because OS developers did not realize the importance of the problem well enough. If something is really needed for solution of the application problem, application developer will use non-graceful approach, so banning asynchronous termination can make things only worse.

I found a real solutions years ago and unfortunately lost the reference to original work. But I can describe it in detail. Please see my past answer: Close correcly the thread inside a dll[^].

On the concept of preemption, please read: http://en.wikipedia.org/wiki/Preemption_%28computing%29[^].

One final note. The solution described above is save and efficient, but it was never accepted in Windows API. Nevertheless, it made it way into much wiser API, which is .NET. This is how .NET FCL Thread.Abort works.

This issue is very complex and non-trivial, so your follow-up questions will be very welcome.

—SA


这篇关于改进线程同步机制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆