C++/MFC/ATL 线程安全字符串读/写
C++/MFC/ATL Thread-Safe String read/write
我有一个启动线程的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?
}
你可以实现某种无锁的方式来实现这一目标,但这取决于你如何使用MyClass和你的线程。如果你的线程正在处理一些数据,并且在处理它之后,它需要更新MyClass,那么考虑把你的字符串数据放在其他一些类中,例如:
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_pstrDataForThreads
分配给m_pstrData
,并分配新的m_pstrDataForThreads
,
问题在于如何安全地删除m_pstrData,我想你可以在这里使用 std::shared_ptr。
最后,它看起来有点复杂,IMO 真的不值得付出努力,至少很难判断这是否真的是线程安全的,以及何时代码会变得更加复杂 - 它仍然是线程安全的。这也适用于单个工作线程的情况,并且您说您有多个线程。这就是为什么关键部分是一个起点,如果它太慢,请考虑使用无锁方法。
顺便说一句,根据字符串数据的更新频率,您还可以考虑使用 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;
我会使用更简单的方法,用SetStrInfo
保护变量:
void SetStrInfo(const CString& str)
{
[Lock-here]
m_strInfo = str;
[Unlock-here]
}
对于锁定和解锁,我们可以使用CCriticalSection
(类的成员),或者将其包裹CSingleLock
RAII。出于性能原因,我们也可能使用超薄读取器编写器锁(使用 RAII 包装 - 编写一个简单的类)。我们还可能使用更新的C++技术进行 RAII 锁定/解锁。
叫我老派,但对我来说std
命名空间有一组复杂的选项——并不适合所有人。
- 以线程安全的方式转换 C/C++ 中时区名称字符串的时区偏移量
- 返回从字符串文本创建的静态string_view是否安全?
- 是否有一种安全的方法可以断言字符串视图是否以 null 终止?
- 为什么在构造函数中将字符串分配给指针是安全的?
- 是否有很好的C 实现安全字符串
- 最快和/或最安全的方法,在C 中加入两个宽字符串
- 假设浮点数或双 NaN 将始终作为字符串"nan"是否安全?
- std::串联的字符串引用是安全的
- 如何在C++中使类型安全字符串"definition"对象?
- 插入没有空终止符空间的字符串是否安全?
- 在 C++98 中写入单个字符串以"线程安全"吗
- 将 const 引用传递给临时字符串对象在 C++ 中安全吗?
- 这种反转字符串的方式安全吗?
- 为什么我可以通过这样的字符串参数?这种样式安全吗?
- 从字符串中读取溢出双倍作为'inf'的安全方法
- 键入安全字符串参数
- 在C代码中安全嵌入字符串(安全字符串,安全字符*)
- 安全C++ std::字符串到 TCHAR * 转换
- std::字符串 在安全位置截断 UTF-8 的最佳方法
- 剪切字符串的字符串安全方式(Windows内核)