繁体   English   中英

哪些是从线程通过 PostMessage 发送 CString 的安全方法

[英]Which are the safe way to send CString through PostMessage from thread

从线程通过PostMessage发送CString的安全/最佳方式是什么? 在堆上创建CString并在接收者获得此CString时进行清理?

解决方案1:在线程中:

CString* pError = new CString(_T("Unknown error"));
::PostMessage(...(LPARAM)pError);

在主线程中,在 GUI 的某个地方:

CString* pError = (CString*)lParam;
GetDocument()->DoSomething(*pError);
delete pError;

解决方案 2:或者,将CString对象保留为CThread类内部的成员变量?

class CPlanThread : public CThread [: public CObject]
{
public:
DECLARE_DYNAMIC(CPlanThread)

...
protected:
CString* m_pMessage;

};

CPlanThread::CPlanThread()
:m_pMessage(NULL)
{
m_pMessage = new CString(_T(""));
}

CPlanThread::~CPlanThread()
{
if(NULL != m_pMessage)
    delete m_pMessage;
}

和线程中的某个地方:

::PostMessage(m_hWndMain, WMU_NOTIFYTHREAD, 0, (LPARAM)m_pMessage);

在主线程中,在 GUI 的某个地方:

CString* pError = (CString*)lParam;
GetDocument()->DoSomething(*pError);

以上两种解决方案都安全吗? 感谢您的任何解释。

第一种选择是更安全的选择。 *这可能导致资源泄漏的唯一原因是,如果对::PostMessage的调用失败,并且您没有在发送::PostMessage进行清理。 请注意,这不会导致崩溃。

第二种选择会产生竞争条件,因为您持有一个指针,您打算转让其所有权。 如果 GUI 线程在线程对象被销毁后尝试访问该字符串,则您正在访问随机内存。 如果幸运的话,这可能会导致立即崩溃。

根据您的特定用例,您可能需要考虑使用第三种选择:使用具有自动存储持续时间和通过消息发送进行线程同步的CString对象,例如:

CStringW err( L"Unknown error" );
::SendMessage( ..., (LPARAM)&err );

只要字符串对象在其消息处理程序中,接收线程就可以使用它,并且发送者将自动清理资源。


*假设两个线程都在同一个模块中实现。 请务必阅读Potential Errors Passing CRT Objects Across DLL Boundaries ,以防万一。

我总是更喜欢将东西存储在成员变量中(这意味着有一个对象负责清理它们)。 但是,请参阅下面的一个重要警告。 我也更喜欢按值保存 CString,而不是按指针。 存储指针只会让您需要管理另一块内存。 所以:

class CPlanThread : public CThread [: public CObject]
{
public:
DECLARE_DYNAMIC(CPlanThread)

...
protected:
CString m_Message;

};
and

CPlanThread::CPlanThread()
:m_Message(L"")
{
}

CPlanThread::~CPlanThread()
{
}

进而

::PostMessage(m_hWndMain, WMU_NOTIFYTHREAD, 0, (LPARAM)&m_Message);

请注意,这种方法意味着您不需要在析构函数中执行任何操作,并且构造函数可以初始化变量(实际上,您应该对指针使用初始化)。

我已经删除了_T()宏。 这是一个非常糟糕的主意,除非您实际上使用两种类型的字符构建了软件版本(这会使您的测试工作加倍而没有任何好处)。 习惯于用前导'L'来写你的文字。

最后的评论,在删除指针之前测试指针是否为nullptr毫无意义 - delete 无论如何都会进行检查。

重要警告

这种方法意味着您需要确保CPlanThread对象在处理消息之前一直存在 - 但无论如何您都必须对指针成员执行此操作。

如果你不能确保生命周期,但你可以只使用字符串文字,那么发布一个const wchar_t*并且你不必管理生命周期。

如果您不能确保生命周期足够长,并且您不能只使用文字,那么您将不得不使用 new/delete 方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM