The use of c/c + + multi thread unique lock

Keywords: C++ github

The use of multi thread unique lock

Features of unique lock:

1. Flexible. You can create an instance of unique_lock without locking, and then manually call the lock_a.lock() function, or std::lock(lock_a,...) ), to lock. When the instance of unique lock is destructed, the unlock function will be called automatically to release the lock.

unique_lock<mutex> lock_a(d1.m, std::defer_lock);

2. The instance of unique lock can call the unlock function. This means that you can choose to release the lock in the branch of the program before destroying the instance of unique lock. Holding a lock for longer than it takes may cause performance degradation, as other threads waiting for the lock are blocked from running for longer than it takes.

Note: there is a drawback. When the lock is not owned, the unlock member method is called and the program crashes. The crash information is as follows:

terminate called after throwing an instance of 'std::system_error'
  what():  Operation not permitted
Aborted (core dumped)

3. Ownership of locks can be transferred between scopes. If the value is right, it will be transferred automatically; if the value is left, the std::move() function must be called manually to transfer the ownership of the lock.

This mode is usually used where the mutex to be locked depends on the current state of the program, or on the function passed back to the STD:: unique'lock object.

Example: about the first and second points above

#include <list>
#include <iostream>
#include <mutex>
#include <algorithm>
#include <thread>
#include <unistd.h>

using namespace std;
class data_protect;
void swap(data_protect& , data_protect& );
//Is thread safe
class data_protect{
  friend void swap(data_protect& , data_protect& );
private:
  list<int> alist{1,2};
  mutex m;
public:  
  void add_list(int val){
    //When operating the two-way linked list, it is locked
    lock_guard<mutex> g(m);
    alist.push_back(val);
  }
  bool contains(int val){
    //When operating the two-way linked list, it is locked
    lock_guard<mutex> g(m);
    return find(alist.begin(), alist.end(), val) != alist.end();
  }
};

void swap(data_protect& d1, data_protect& d2){
  //if(d1 == d2) return;

  //Deadlock
  //d1.add_list(11);
  unique_lock<mutex> lock_a(d1.m, std::defer_lock);
  unique_lock<mutex> lock_b(d2.m, std::defer_lock);
  std::lock(lock_a, lock_b);
  swap(d1.alist, d2.alist);

  //There are unlock member functions, and the unlock function can be called manually
  //If the lock is not held, calling the unlock member function will cause the program to crash. So check if you have a lock.
  if(lock_a.owns_lock() && lock_b.owns_lock()){
    lock_a.unlock();
    lock_b.unlock();
  }
}
int main(){
  data_protect d1, d2;
  swap(d1, d2);
  d2.add_list(11);
}

github source code

Example: on the third point above

#include <mutex>

std::unique_lock<std::mutex> getlock(){
  std::mutex sm;
  std::unique_lock<std::mutex> lk(sm);
  //prepare_data();
  return lk;//Because lk is the right value, the std::move function is called automatically to transfer the ownership of the lock.
}

void process_data(){
  std::unique_lock<std::mutex> lk(getlock());
  //do_something();
}

int main(){
  process_data();
}

github source code

QQ group of mutual learning in c/c + +: 877684253

My wechat: xiaoshitou5854

Posted by Robkid on Mon, 09 Dec 2019 22:46:02 -0800