gpt4 book ai didi

c++ - 非阻塞线程同步

转载 作者:太空宇宙 更新时间:2023-11-04 11:51:05 25 4
gpt4 key购买 nike

我有一个带有按钮和一些其他控件的对话框。

当按下该按钮时,会生成一个工作线程。

为了便于讨论,我们只说线程函数做的工作很长。

每次单击按钮时,都会产生新的线程并执行它的操作。

对话框在工作线程执行它们的工作时不应该被阻塞,因为用户应该能够最小化它,点击其他控件等等。

在维基百科上,我找到了一个术语lock-free algorithm,它指的是非阻塞线程同步。

这就是我对非阻塞线程同步感兴趣的原因。我相信这将确保我需要的行为。

我是多线程的新手,但我确实在这里找到了一些关于它的文章/回答了问题,并阅读了关于它的 Microsoft 文档。

其中大部分使用以下算法:

1.

主线程声明一个 volatile 变量(通常是 int 或 bool )并将其传递给工作线程。工作线程在循环中检查变量,如果未设置为指示其终止,则继续执行其工作。当需要终止时,父线程设置变量。

2.

Microsoft 的网站上还有大量关于同步的文档。在那里,我发现了互斥锁、临界区、互锁等等。

这些问题是它们总是阻塞父线程(通常使用 WaitForSingleObject 或 WaitForMultipleObjects API),直到工作线程完成。

另外,在这里搜索时,我发现了一个最近的问题 ( Abort thread properly when dialog box close button is clicked ),它帮助我开始了。

为了解决我的问题,我将把这个问题分成多个问题,并分别发布,以尊重 StackOverflow 的规则。

所以我现在的第一个问题是:

我应该使用哪种 API/算法来实现非阻塞线程同步,这将帮助我实现上述对话框的行为?

如果可能的话,我也希望能链接到教程或代码示例,因为我在 Google 上运气不好(另外,开发人员通过代码/伪代码学习得最好)。

我将在下面展示我对这些代码片段的初步尝试,以防它们被证明是有用的:

   // thread function

DWORD WINAPI MyThread()
{
int result = 0;

// do something

if( /** everything is OK **/ )
return result;
else
{
result = 1;

return result;
}
}

现在对话框:

  // button clicked handler

case IDC_BUTTON1:
{
// create thread

DWORD tID;

HANDLE th = CreateThread( NULL , 0 ,
(LPTHREAD_START_ROUTINE)MyThread ,
NULL , 0 , &tID );

if( !th )
EndDialog( hWnd, IDCANCEL );

CloseHandle( th );
}
break;

case IDCANCEL:

EndDialog( hWnd, IDCANCEL );

break;

此时,当我运行程序、激活对话框并单击按钮时,工作线程就会启动,如果我等待它完成就可以了。

然而,如果我提前关闭对话框,我的问题的性质与我在这里发现的问题相同(我认为 IDCANCEL 处理程序中的 WaitForMultipleObjects 可以部分解决这个问题,但我会把它留到另一篇文章)。

编辑#1:

我发布了新代码,以反射(reflect)我的进步和遇到的问题。

重要提示:

我没有启动多个线程,而是隐藏了启动线程的按钮,一旦按下它。

这意味着用户必须等待第一个线程完成,然后他/她才能激活第二个线程。

这样做是为了更容易调试。

定义了自定义消息以指示线程是正常退出还是发生错误。

    #define WM_THREAD_OK      ( WM_APP + 1 )

#define WM_THREAD_ERROR ( WM_APP + 2 )

添加了将传递给线程的数据结构,以便它可以与对话框通信,因此可以正确中止

    struct Data
{
HWND hwnd;

bool bContinue;
};

重新设计线程函数以将消息发送到对话框,以便它可以通知对话框有关错误或正常结束。

新代码(这是基于 Charles Petzold-Programming Windows 第五版一书中的示例):

   // thread function

DWORD WINAPI MyThread( LPVOID lpvoid )
{

HRESULT hr;

volatile Data *data = ( Data* )lpvoid;

try
{
for( int i = 0; i < 10 && data->bContinue; i++ )
{
hr = // do something

if( FAILED(hr) )
throw _com_error(hr);
}

// once you leave loop, check if thread was aborted, or all was well

if( ! ( data->bContinue ) )
{
// thread was aborted, do cleanup and exit

// cleanup

return 0;
}

// if all went well, do cleanup, and "say" so to the dialog box

// do cleanup here

SendMessage( data->hwnd, WM_THREAD_OK, 0, 0 );

return 0; // exit gracefully
}
catch( _com_error & )
{
// do cleanup

SendMessage( data->hwnd, WM_THREAD_ERROR, 0, 0 );

return 1;
}
}

这是对话框的新代码(注意:对话框现在是无模式的):

  static Data data;

HANDLE th = NULL;

// button clicked handler

case IDC_BUTTON1:
{
// create thread

DWORD tID;

th = CreateThread( NULL , 0 ,
(LPTHREAD_START_ROUTINE)MyThread ,
(LPVOID)&data, 0 , &tID );

if( !th )
DestroyWindow( hwnd );

// hide the button which activates thread

ShowWindow( GetDlgItem( hwnd, IDC_BUTTON1 ), SW_HIDE );
}
break;

case WM_THREAD_OK:

if( th )
CloseHandle( th );

ShowWindow( GetDlgItem( hwnd, IDC_BUTTON1 ), SW_SHOW );

break;

case WM_THREAD_ERROR:

if( th )
CloseHandle( threadHandle );

MessageBox( hwnd, L"Error", L"Error", MB_ICONERROR );

break;

case IDCANCEL:

data.bContinue = false; // set thread abortion flag

if( th )
{
// after I comment out below statement, thread aborts properly

// WaitForSingleObject( th, INFINITE );

CloseHandle( th );
}

DestroyWindow( hwnd ); // dialog box is now modeless one!

break;

我的问题是:这段代码有没有错误?能否改进,如何改进?

谢谢。

最佳答案

你不需要无锁同步。只需启动线程并让它们在完成时向对象发出信号。如果您不想阻塞 UI 线程,请对同步句柄执行非阻塞调用

WaitForMultipleObjects(n,lpHandles, 0, 0);

如果对象没有发出信号,最后一个 0 表示返回而不是等待

关于c++ - 非阻塞线程同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18197677/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com