从线程通过PostMessage发送CString的安全/最佳方法是什么? 在堆上创建CString并在接收者获得此CString时进行清理?
解决方案1:在主题中:
var options = new OpenIdConnectOptions();
options.Scope.Clear();
options.Scope.Add("openid");
app.UseOpenIdConnectAuthentication(options);
并在主线程中,GUI中的某个地方:
CString* pError = new CString(_T("Unknown error"));
::PostMessage(...(LPARAM)pError);
解决方案2: 或者,将CString对象保留为CThread类中的成员变量?
CString* pError = (CString*)lParam;
GetDocument()->DoSomething(*pError);
delete pError;
和
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;
}
并在主线程中,GUI中的某个地方:
::PostMessage(m_hWndMain, WMU_NOTIFYTHREAD, 0, (LPARAM)m_pMessage);
以上两种解决方案都安全吗?请您解释任何解释。
答案 0 :(得分:3)
第一个选择是更安全的替代方案。 * 唯一的原因,如果对::PostMessage
的调用失败,并且您没有清理,这可能导致资源泄漏的原因在发件人中。请注意,这不会导致崩溃。
第二种方法会创建一个竞争条件,因为你要抓住一个指针,你想要转移它的所有权。如果GUI线程在线程对象被销毁后尝试访问该字符串,则表示您正在访问随机存储器。如果你幸运的话,这可能导致立即崩溃。
根据您的具体用例,您可能需要考虑使用第三种方法:使用具有自动存储持续时间的CString
对象和通过消息发送进行线程同步,例如:
CStringW err( L"Unknown error" );
::SendMessage( ..., (LPARAM)&err );
接收线程可以使用字符串对象,只要它在消息处理程序中,并且发送方将自动清理资源。
<小时/> * 假设两个线程都在同一个模块中实现。如果不是,请务必阅读Potential Errors Passing CRT Objects Across DLL Boundaries。
答案 1 :(得分:2)
我总是喜欢将事物存储在成员变量中(这意味着有一个对象负责清理它们)。但是,请参阅下面的重要警告。我也更喜欢按值而不是指针来保存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()
宏。这是一个非常糟糕的主意,除非您实际构建具有两种类型角色的软件版本(这会使您的测试工作加倍并没有任何好处)。只需习惯用领先的&#39; L&#39;来编写您的文字。
最终评论,如果指针在删除前是nullptr
没有必要进行测试 - 无论如何删除都会进行检查。
这种方法意味着您需要确保CPlanThread
对象存在,直到处理完消息后 - 但无论如何您必须使用指针成员执行此操作。
如果您无法确保生命周期,但您可以使用字符串文字,那么发布const wchar_t*
并且您不必管理生命周期。
如果你不能确保生命周期足够长,并且你不能只使用文字,那么你将不得不使用新的/删除方法。