我有以下代码:
标题:
class Counter
{
public:
Conuter(const std::string& fileName);
boost::uint16_t getCounter();
private:
tbb::atomic<boost::uint32_t> counter;
std::string counterFileName;
};
cpp:
Counter::Counter(const std::string& fileName) : counter(), counterFileName(fileName)
{
std::string line;
std::ifstream counterFile (fileName.c_str());
if (counterFile.is_open())
{
getline (counterFile, line);
counterFile.close();
}
boost::uint32_t temp = std::stoul (line,nullptr,0);
counter = temp;
}
boost::uint32_t Counter::getCounter()
{
if (counter > 1000)
{
counter = 0;
}
assert( counter < 1000);
const boost::uint32_t ret = counter++;
if ((counter % 10) == 0)
{
// write the counter back to the file.
std::ofstream file (counterFileName.c_str());
if (file.is_open())
{
myfile << counter;
myfile.close();
}
}
return ret;
}
其他地方可以说我们有两个主题:
boost::thread t1(&Counter::getCounter, counter);
boost::thread t2(&Counter::getCounter, counter);
我的问题是围绕原子变量。由于getCounter函数每次调用最多可以访问计数器值3次,因此原子变量可以从一次调用更改为下一次调用。例如,如果对if(counter&gt; 1000)的调用未能通过,那么断言是否也会通过?也许更具体地说,原子变量阻塞直到函数调用结束?或者只要读取/写入值即可?我的第二个问题是,操作系统如何处理原子?如果原子没有导致函数阻塞直到它完成,如果一个线程正在更新变量并且一个线程试图将其写出来会发生什么?很抱歉这是我第一次尝试无锁数据结构。
答案 0 :(得分:5)
首先,即使在单线程应用程序中,
的序列if (counter > 1000) ...
assert(counter < 1000)
当计数器为1000时,将失败。
第二,是的,原子变量可以很容易地在读取之间改变。它的全部意义在于单个读取是原子的,如果另一个线程在读取时正确地更新变量,那么您可以保证有一个正确的内存排序读取(您还可以对其上的算术有一些保证 - 您的增量保证增加)。但它没有说下一次阅读!
如果您需要锁定变量,则需要使用锁定机制,例如互斥锁。