2015-06-19 211 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命名空間有一套複雜的選項 - 並不適合所有人以及所有人。