通过比较以下几种同步方式,测试各方法效率,分为以下6种情况做对比:
- 不加任何同步措施;
- Windows原子操作;
- c++11 mutrex;
- 自定义的自旋锁CLCS;
- Windows临界区;
- Windows互斥对象;
硬件平台:AMD 8核16线程,内存16GB
系统/软件平台:windows10,vs2019com(vc++);
方法:定义3个变量,在多线程中自加(16线程x10万次),记录时间并考察结果正确性;
结果如下:
结论 :
- 不加锁,速度极快,但结果是不可预测的错误值,没有应用价值。
- windows原子操作 及 c++11中的mutrex效率非常高;
【让人不可思议的是,c++的mutrex锁的实现效率非常高,接近了原子操作的效率,这一点非常让人意外,一直以为c++锁会由于跨平台要求和底层调用封装,而会慢于windows临界区,看来这是不
对的。通过查看mutrex在windows vc 上面的底层实现,发现原来是使用了windows7才加入 SRWLock锁(读写锁),也就是在windows vista及以前的windwos平台仍然使用的临界区,而windows7平台用SRWLock锁替代了,而进一步剖析SRWLock的底层实现,仍然是用的原子自旋锁,这也解释了为什么c++mutrex在win7及以上的平台效率和原子锁效率相同的原因】 - 自定义的自旋锁,速度可以实现得很精简,效率略高于Windows临界区的效率,毕竟摆脱了一些多余的调用过程;
- Windows临界区效率尚可,但仍然是原子操作和c++锁的所需时间的10倍以上;
- Windows互斥对象,由于实现跨进程同步,需要进入系统内核进行调度,所以比较慢,耗时是临界区的10倍以上;
以下是测试代码:
【 并行化支持】
int main() {
const size_t times = 100000;
size_t a = 0, b = 0, c = 0;
CLAtomic<size_t> aa = 0, ba = 0, ca = 0; //原子对象
CLCS cs;
CLCSLock cs2;
TaskPoolStatic volatile as;
CLTick tk; //高精度定时器
tk.timingStart();
parallel_proc([&](int ci, int n) {
//并行化
for (size_t i = 0; i < times; i++)
{
++a; ++b; ++c;
}
});
auto s0_ = tk.getSpendTime();
cout << "\nno lock: " << a << " , " << b << " , " << c << " , time = " << s0_ << " , error ...";
tk.timingStart();
parallel_proc([&](int ci, int n) {
for (size_t i = 0; i < times; i++)
{
++aa;++ba;++ca;
}
});
auto s0 = tk.getSpendTime();
cout << "\nAtomic: " << aa() << " , " << ba() << " , " << ca() << " , time = " << s0;
a = 0, b = 0, c = 0;
mutex cs3;
tk.timingStart();
parallel_proc([&](int ci, int n) {
for (size_t i = 0; i < times; i++)
{
cs3.lock(); ++a; cs3.unlock();
cs3.lock(); ++b; cs3.unlock();
cs3.lock(); ++c; cs3.unlock();
}
});
auto s4 = tk.getSpendTime();
cout << "\nc++11 mutex: " << a << " , " << b << " , " << c << " , time = " << s4;
a = 0, b = 0, c = 0;
tk.timingStart();
parallel_proc([&](int ci, int n) {
for (size_t i = 0; i < times; i++)
{
cs.lock(); ++a; cs.unlock();
cs.lock(); ++b; cs.unlock();
cs.lock(); ++c; cs.unlock();
}
});
auto s1 = tk.getSpendTime();
cout << "\nclcs: " << a << " , " << b << " , " << c << " , time = " << s1;
a = 0, b = 0, c = 0;
tk.timingStart();
parallel_proc([&](int ci, int n) {
for (size_t i = 0; i < times