2015-06-19 195 views
1

我有一个启动线程的MFC类,线程需要修改主类的CString成员。线程安全字符串读取/写入

我讨厌互斥锁,所以必须有一个更简单的方法来做到这一点。

我想使用boost.org库或atl :: atomic或shared_ptr变量。

什么是读写字符串和线程安全的最佳方法?

class MyClass 
{ 
    public: 
     void  MyClass(); 
     static UINT MyThread(LPVOID pArg); 
     CString  m_strInfo; 
}; 

void MyClass::MyClass() 
{ 
    AfxBeginThread(MyThread, this); 
    CString strTmp=m_strInfo; // this may cause crash 
} 

UINT MyClass::MyThread(LPVOID pArg) 
{ 
    MyClass pClass=(MyClass*)pArd; 
    pClass->m_strInfo=_T("New Value"); // non thread-safe change 
} 

根据MSDN shared_ptr的自动工作https://msdn.microsoft.com/en-us/library/bb982026.aspx

所以这是一个更好的方法?

#include <memory> 
class MyClass 
{ 
    public: 
     void  MyClass(); 
     static UINT MyThread(LPVOID pArg); 
     std::shared_ptr<CString> m_strInfo; // ******** 
}; 

void MyClass::MyClass() 
{ 
    AfxBeginThread(MyThread, this); 
    CString strTmp=m_strInfo; // this may cause crash 
} 

UINT MyClass::MyThread(LPVOID pArg) 
{ 
    MyClass pClass=(MyClass*)pArd; 
    shared_ptr<CString> newValue(new CString()); 

    newValue->SetString(_T("New Value")); 
    pClass->m_strInfo=newValue; // thread-safe change? 
} 
+2

使用RAII管理锁定生命期的关键部分。 –

回答

1

您可以实现某种无锁的方式来实现这一目标,但它取决于你如何使用MyClass的和你的线程。如果您的线程正在处理一些数据,并对其进行处理后,它需要更新MyClass的,然后再考虑把你的字符串数据在其他一些类ex:

struct StringData { 
    CString  m_strInfo; 
}; 

那么你的MyClass的内部:

class MyClass 
{ 
    public: 
     void  MyClass(); 
     static UINT MyThread(LPVOID pArg); 
     StringData*  m_pstrData; 
     StringData*  m_pstrDataForThreads; 
}; 

现在,这个想法是在你的ie。主线程代码使用m_pstrData,但你需要使用原子能存储本地指针,它即:

void MyClass::MyClass() 
{ 
    AfxBeginThread(MyThread, this); 

    StringData* m_pstrDataTemp = ATOMIC_READ(m_pstrData); 
    if (m_pstrDataTemp) 
     CString strTmp=m_pstrDataTemp->m_strInfo; // this may NOT cause crash 
} 

一旦你的线程完成数据处理,并且要更新的字符串,你会原子分配m_pstrDataForThreadsm_pstrData,并分配新的m_pstrDataForThreads,

问题是如何安全地删除m_pstrData,我想你可以在这里使用std :: shared_ptr。

最终它看起来有些复杂,IMO并不值得付出努力,至少很难说这是否真的是线程安全的,并且代码会变得更复杂 - 它仍然是线程安全的。这也适用于单个工作线程的情况,并且你说你有多个线程。这就是为什么关键部分是一个起点,如果它太慢,那么考虑使用无锁方法。

btw。取决于字符串数据更新的频率,您还可以考虑使用PostMessage将指针安全地传递给新字符串,以便将其传递到主线程。

[编辑]

ATOMIC_MACRO不存在,它只是一个占位符,使其编译使用即。 C++ 11个原子学,例如下面:

#include <atomic> 
... 
std::atomic<uint64_t> sharedValue(0); 
sharedValue.store(123, std::memory_order_relaxed);   // atomically store 
uint64_t ret = sharedValue.load(std::memory_order_relaxed); // atomically read 
std::cout << ret; 
+0

我有6个线程,它们从OnInitDialog开始,然后当它们完成时,值将显示在对话框中。 –

+0

但您怎么看待shared_ptr ? –

+1

shared_ptr 看起来不错,我会反正在你的情况下使用PostMessage,这里是例子:http://stackoverflow.com/questions/10719902/postmessage-from-workerthread-to-main-window-in-mfc – marcinj

1

我会通过保护变量与SetStrInfo已经使用更简单的方法:

void SetStrInfo(const CString& str) 
{ 
    [Lock-here] 
    m_strInfo = str; 
    [Unlock-here] 
} 

用于锁定和解锁我们可能会使用CCriticalSection(类的成员) ,或围绕CSingleLock RAII包装。出于性能原因,我们也可能使用slim-reader writer locks(用RAII包装 - 写一个简单的课程)。我们也可以使用更新的C++技术来实现RAII锁定/解锁。

打电话给我老派,但对我来说std命名空间有一套复杂的选项 - 并不适合所有人以及所有人。