这段代码是否被认为是线程安全的? 当我使用缓冲区时,它有时会崩溃,我认为它会导致数据竞争问题,这个实现有什么问题吗?
TSByteBuf.cpp
#include "TSByteBuf.h"
int TSByteBuf::Read(byte* buf, int len)
{
while (true)
{
if (isBusy.load())
{
//Sleep(10);
}else
{
isBusy.store(true);
int dByteGet = m_buffer.sgetn((char*) buf, len);
isBusy.store(false);
return dByteGet;
}
}
}
int TSByteBuf::Write(byte* buf, int len)
{
while (true)
{
if (isBusy.load())
{
//Sleep(10);
}else
{
isBusy.store(true);
int dBytePut = m_buffer.sputn((char*) buf, len);
isBusy.store(false);
return dBytePut;
}
}
}
TSByteBuf.h
#ifndef TSBYTEBUF_H
#define TSBYTEBUF_H
#include <sstream>
#include <atomic>
typedef unsigned char byte;
class TSByteBuf
{
public:
std::stringbuf m_buffer;
//bool Write(byte* buf, int len);
//bool Read(byte* buf, int len);
int Write(byte* buf, int len);
int Read(byte* buf, int len);
protected:
std::atomic<bool> isBusy;
};
#endif
答案 0 :(得分:2)
尝试设置isBusy
变量的线程之间存在竞争。使用std::atomic<>
,加载和存储保证是原子的,但在代码中的这两个操作之间有一个时间窗口。您需要使用一组不同的函数,这些函数以原子方式提供两个函数。请参阅compare_exchange。
使用C ++标准库提供的工具,您可以让您的生活更轻松。要确保一次只有一个线程访问给定区域(具有独占访问权限),您可以使用std::mutex
。此外,您可以使用std::lock_guard
,它会自动锁定(并在示波器的末尾解锁)互斥锁。
int TSByteBuf::Read(byte* buf, int len)
{
std::lock_guard<std::mutex> lg(mutex);
// do your thing, no need to unlock afterwards, the guard will take care of it for you
}
需要在线程之间共享mutex
变量,使其成为类的成员变量。
如果要确保线程永远不会进入休眠状态,可以通过创建自己的锁定机制来使用std::mutex
。正如评论中指出的那样,您可能不需要这样做,std::mutex
的用法就可以了。我把它留在这里只是为了参考。
class spin_lock {
public:
spin_lock() : flag(ATOMIC_FLAG_INIT) {}
void lock() {
while (flag.test_and_set(std::memory_order_acquire))
;
}
void unlock() { flag.clear(std::memory_order_release); }
private:
std::atomic_flag flag;
};
请注意使用更轻量级的std::atomic_flag
。现在你可以使用这样的类:
int TSByteBuf::Read(byte* buf, int len)
{
std::unique_lock<spin_lock> lg(spinner);
// do your thing, no need to unlock afterwards, the guard will take care of it for you
}
答案 1 :(得分:1)
&#34;此实施有任何问题吗?&#34;
我发现的一个问题是,std::atomic<bool> isBusy;
无法替换std::mutex
来锁定m_buffer
的并发访问权限。您从未将值设置为true
。
但即使您这样做(从编辑中看到),store()
值的load()
和isBusy
操作也不会形成锁定以保护对{的访问权限{1}}整体而言。线程上下文切换可能发生在两者之间。