Multithreading uses CAS to replace mutex locks

  1. No locks, thread insecure
#include <chrono>
#include <iostream>
#include <thread>

using namespace std;
using namespace chrono;

int g_sum = 0;

void add(int num) {
    
    
    for (int i = 0; i < 10000000; i++) {
    
    
        g_sum += num;
    }
    return;
}
int main(int argc, char const *argv[]) {
    
    
    auto start = system_clock::now();
    std::thread t1(add, 1);
    std::thread t2(add, 1);
    t1.join();
    t2.join();
    std::cout << "sum:" << g_sum << std::endl;
    auto end = system_clock::now();
    auto duration = duration_cast<microseconds>(end - start);
    cout << "花费了"
         << double(duration.count()) * microseconds::period::num /
                microseconds::period::den
         << "秒" << endl;
    return 0;
}

Output, it can be seen that this block is thread-unsafe, and the data output is different each time

[root@localhost test-codes]# ./simple 
sum:10292677
花费了0.374036秒
[root@localhost test-codes]# ./simple 
sum:11729970
花费了0.417374秒
[root@localhost test-codes]# ./simple 
sum:14425458
花费了0.417321秒
  1. Locking to ensure thread safety, time-consuming 11s
std::mutex g_mutex;
void add(int num) {
    
    
    for (int i = 0; i < 10000000; i++) {
    
    
        std::lock_guard<std::mutex> guard(g_mutex);
        g_sum += num;
    }
    return;
}
[root@localhost test-codes]# ./simple 
sum:50000000
花费了11.5244秒
[root@localhost test-codes]# ./simple 
sum:50000000
花费了11.683秒
[root@localhost test-codes]# ./simple 
sum:50000000
花费了11.3936秒
  1. Using cas, under the correct conditions, the time-consuming is shorter than the mutex lock time, about 8s
void add(int num) {
    
    
    int old_g_sum = g_sum;
    for (int i = 0; i < 10000000; i++) {
    
    
        while (
            !__sync_bool_compare_and_swap(&g_sum, old_g_sum, old_g_sum + 1)) {
    
    
            old_g_sum = g_sum;
        }
    }
    return;
}
[root@localhost test-codes]# ./simple 
sum:50000000
花费了7.90655秒
[root@localhost test-codes]# ./simple 
sum:50000000
花费了8.69977秒
[root@localhost test-codes]# ./simple 
sum:50000000
花费了8.88852秒

Compilation method
g++ -std=c++11 -lpthread -march=nocona -mtune=generic simple.cpp -o simple
If these two parameters are not added, the actual difference between 1 and 2 is not much. These two parameters extend the compilation performance .

As shown in the code above, CAS is actually compare and swap, which retains the old value. Before writing the new value, if the new value and the old value are the same (which can be understood as the same context), the update operation is performed.

CAS is compare and swap. Simply put, before writing the new value, read the old value, and only when the old value is consistent with the current value in the storage, will the new value be written to the storage. It is a popular algorithm that does nothing. It only needs one step of the CPU instruction, so it is fast.

Guess you like

Origin blog.csdn.net/niu91/article/details/109225547