我正在考虑为项目实施队列的选项,其要求是生产者至少必须尽可能低延迟。为此,我一直在研究“无锁”队列,std::atomic
用于控制生产者和消费者线程对数据结构的访问。我希望这将避免代码当前使用的开销std::mutex
,特别是避免开销。std::unique_lock
为此,我编写了一个简单的测试程序来评估std::mutex
(加上std::unique_lock
)和std::atomic
. 该程序还进行检查以确保原子对象是无锁的,它确实是。
#include <mutex>
#include <atomic>
#include <thread>
#include <chrono>
#include <iostream>
#define CYCLES 100000000
void testAtomic()
{
bool var(true);
std::atomic_bool _value(true);
std::cout << "atomic bool is ";
if(!_value.is_lock_free())
std::cout << "not ";
std::cout << "lock free" << std::endl;
const auto _start_time = std::chrono::high_resolution_clock::now();
for(size_t counter = 0; counter < CYCLES; counter++)
{
var = _value.load();
var = !var;
_value.store(var);
}
const auto _end_time = std::chrono::high_resolution_clock::now();
std::cout << 1e-6 * std::chrono::duration_cast<std::chrono::microseconds>
(_end_time - _start_time).count() << " s" << std::endl;
}
void testMutex()
{
bool var(true);
std::mutex _mutex;
std::chrono::high_resolution_clock _clock;
const auto _start_time = std::chrono::high_resolution_clock::now();
for(size_t counter = 0; counter < CYCLES; counter++)
{
std::unique_lock<std::mutex> lock(_mutex);
var = !var;
}
const auto _end_time = std::chrono::high_resolution_clock::now();
std::cout << 1e-6 * std::chrono::duration_cast<std::chrono::microseconds>
(_end_time - _start_time).count() << " s" << std::endl;
}
int main()
{
std::thread t1(testAtomic);
t1.join();
std::thread t2(testMutex);
t2.join();
return 0;
}
运行此程序时,我得到以下输出:
atomic bool is lock free
3.49434 s
2.31755 s
这将向我表明std::mutex
(and std::unique_lock
) 明显更快,这与我阅读有关原子与互斥锁的期望相反。我的发现正确吗?我的测试程序有问题吗?我对两者之间差异的理解不正确吗?
代码在 CentOS7 上使用 GCC 4.8.5 编译