关于多线程互斥,条件变量,上锁与解锁这篇就够了

Multi thread:mutex and varible

  • No lock for two threads
  • Atomic
  • Mutex
    • Mutex: Protect global variable only lock
    • Mutex: Protect global variable with lock and unblock
    • std::mutex::try_lock
  • Conditional variable
    • Print 1-100 with multi-thread
    • Print 100 times "ABCABC" with three-thread

No lock for two threads

#include 
#include 
#include 

using namespace std;

int gu_num=0;
void print(int id){
    for (int i=0;i<5;i++){
    
        ++gu_num;
        cout <<"id = " << id << " ==> " << gu_num << endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main(){

    thread t1(print, 0);
    thread t2(print, 1);
    t1.join();
    t2.join();
    return 0;
}

Output:
g++ -o mutex mutex.cpp -lpthread
./mutex 
id = id = 01 ==>  ==> 22

id = id = 1 ==> 40 ==> 4

id = 1 ==> 5
id = 0 ==> 6
id = 1 ==> 8
id = 0 ==> 8
id = 1 ==> 9
id = 0 ==> 10

Atomic

#include 
#include 
#include 
#include 

using namespace std;

atomic_int gu_num (0);
void print(int id){
    for (int i=0;i<5;i++){

        ++gu_num;
        cout <<"id = " << id << " ==> " << gu_num << endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main(){

    thread t1(print, 0);
    thread t2(print, 1);
    t1.join();
    t2.join();
    return 0;
}

Output:
./mutex 
id = 0 ==> 2id = 
1 ==> 2
id = 1 ==> 3
id = 0 ==> 4
id = 1 ==> 5
id = 0 ==> 6
id = 0 ==> 8
id = 1 ==> 8
id = 0 ==> 9
id = 1 ==> 10

Mutex

Mutex: Protect global variable only lock

#include 
#include 
#include 
#include 
#include 

using namespace std;

int gu_num=0;
//atomic_int gu_num (0);
std::mutex mtx;
void print(int id){
    for (int i=0;i<5;i++){

        mtx.lock();
        ++gu_num;
        cout <<"id = " << id << " ==> " << gu_num << endl;
        //mtx.unlock(); For ti, id=0, it has been blocked here
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main(){

    thread t1(print, 0);
    thread t2(print, 1);
    t1.join();
    t2.join();
    return 0;
}
Output:
./mutex 
id = 0 ==> 1   //In the process of blocking

Mutex: Protect global variable with lock and unblock

#include 
#include 
#include 
#include 
#include 

using namespace std;

int gu_num=0;
//atomic_int gu_num (0);
std::mutex mtx;
void print(int id){
    for (int i=0;i<5;i++){
    
        mtx.lock();
        ++gu_num;
        cout <<"id = " << id << " ==> " << gu_num << endl;
        mtx.unlock();
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main(){

    thread t1(print, 0);
    thread t2(print, 1);
    t1.join();
    t2.join();
    return 0;
}

Output:
./mutex 
id = 0 ==> 1
id = 1 ==> 2
id = 0 ==> 3
id = 1 ==> 4
id = 0 ==> 5
id = 1 ==> 6
id = 1 ==> 7
id = 0 ==> 8
id = 1 ==> 9
id = 0 ==> 10

std::mutex::try_lock

  • try_lock success: return true
  • try_lock fail: return false
Wrong example
#include 
#include 
#include 
#include 
#include 

using namespace std;

int gu_num=0;
std::mutex mtx;

void print(int id){
    int result=1;

    for (int i=0;i<5;i++){
        mtx.try_lock();
        result = mtx.try_lock();
        ++gu_num;
        cout << "try_lock result: " << result << "id = " << id << " ==> " << gu_num << endl;
        mtx.unlock();
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main(){

    thread t1(print, 0);
    thread t2(print, 1);
    t1.join();
    t2.join();
    return 0;
}

Output:
./mutex 
//try_lock failed, still rn, no blocking
try_lock result: 0id = 0 ==> 2try_lock result: 
0id = 1 ==> 2
try_lock result: try_lock result: 0id = 0id = 1 ==> 40 ==> 4

try_lock result: 0id = 1 ==> 5
try_lock result: 0id = 0 ==> 6
try_lock result: 0id = 1 ==> 7
try_lock result: 0id = 0 ==> 8
try_lock result: 0id = 1 ==> 9
try_lock result: 0id = 0 ==> 10
Rright example
#include 
#include 
#include 
#include 
#include 

using namespace std;

int gu_num=0;
std::mutex mtx;

void print(int id){

    for (int i=0;i<5;i++){

        while(!mtx.try_lock()){

            cout << " failed "  << endl;
        }
        ++gu_num;
        cout << "Success: id = " << id << " ==> " << gu_num << endl;
        mtx.unlock();
        std::this_thread::sleep_for(std::chrono::microseconds(200));
    }
}

int main(){

    thread t1(print, 0);
    thread t2(print, 1);
    t1.join();
    t2.join();
    return 0;
}

Output:
./mutex 
Success: id = 0 ==> 1 
failed 
Success: id = 1 ==> 2
Success: id = 0 ==> 3
Success: id = 1 ==> 4
Success: id = 0 ==> 5
Success: id = 1 ==> 6
Success: id = 0 ==> 7
Success: id = 1 ==> 8
Success: id = 0 ==> 9
Success: id = 1 ==> 10

Conditional variable

  • Notify the blocked thread that the global variable value changed
    notify_all,notify_all
  • Block a thread to be waited until this thread was notified
    wait,wait_for

Print 1-100 with multi-thread

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

int n=100;
int i =1 ;
//std::mutex mtx;

void print(){
    for(i=1;i<=n;i++){
        cout << "Line" << i << ": "<< i <<endl; 
        }
    }

int main(){

    clock_t start,end;
    start = clock();
    thread t(print);
    t.join();
    end = clock();
    cout << "Run : " << (end - start) << endl;
    cout << "i= " << (i-1) <<endl;
    return 0;
}

Output:
Line1: 1
Line2: 2
Line3: 3
Line4: 4
........
Line97: 97
Line98: 98
Line99: 99
Line100: 100
Run : 165
i= 100

Print 100 times “ABCABC” with three-thread

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
std::mutex mtx;
std::condition_variable cv;
int i=0;
int isReady = 0;
const int n = 100;

void printA(){

    std::unique_lock<std::mutex> lck(mtx); //unique_lock can auto unlock
    while(i<=n){
        while(isReady !=0){
            cv.wait(lck); //isReady = 0 ia a signal to notify printA, so if isReady!0,A should be waiting 
        }
        isReady=1;
        if(i>=n){
            cv.notify_all();
            break;
        }
        ++i;
        cout << "threadA :  " << i << endl ;
        cv.notify_all();
    }
    cout << "threadA Finish!" << endl;
}

void printB(){

    std::unique_lock<std::mutex> lck(mtx);
    while(i<=n){
        while(isReady !=1){
            cv.wait(lck);
        }
        isReady=2;
        if(i>=n){
            cv.notify_all();
            break;
        }
        ++i;
        cout << "threadB :  " << i << endl ;
        cv.notify_all();
    }
    cout << "threadB Finish!" << endl;
}

void printC(){

    std::unique_lock<std::mutex> lck(mtx);
    while(i<=n){
        while(isReady !=2){
            cv.wait(lck);
        }
        isReady=0;
        if(i>=n){
            cv.notify_all();
            break;
        }
        ++i;
        cout << "threadC :  " << i << endl ;
        cv.notify_all();
    }
    cout << "threadC Finish!" << endl;
}

int main(){

    clock_t start,end;
    start = clock();

    thread A(printA);
    thread B(printB);
    thread C(printC);

    A.join();
    B.join();
    C.join();
    end = clock();
    cout << endl << "i= " << i << endl;

    cout << "Run : " << (end - start) << endl;

    return 0;
}

Output:
threadA :  1
threadB :  2
threadC :  3
threadA :  4
.......
threadA :  97
threadB :  98
threadC :  99
threadA :  100
threadB Finish!
threadC Finish!
threadA Finish!

i= 100
Run : 931
+-----------------------------------------+
|    Three-thread print "ABC" until 100   |
+-----------------------------------------+
                     |                     
                     V                     
               /-----------\ N             
               |   i<100   |-------------+ 
               \-----------/             | 
                     | Y                 | 
                     V                   | 
              +-------------+            | 
              |    printA   |            | 
              +-------------+            | 
                     |                   | 
                     V                   | 
       N /-----------------------\       | 
     +---|   Get printC notify   |<--+   | 
     |   \-----------------------/   |   | 
     |               | Y             |   | 
     |               V               |   | 
     |       +---------------+       |   | 
     |       |   print "A"   |       |   | 
     |       +---------------+       |   | 
     |               |               |   | 
     |               V               |   | 
     |       +---------------+       |   | 
     |       |   isReady=1   |       |   | 
     |       +---------------+       |   | 
     |               |               |   | 
     |               V               |   | 
     |          +---------+          |   | 
     |          |   ++i   |          |   | 
     |          +---------+          |   | 
     |               |               |   | 
     |               V               |   | 
     |     +-------------------+     |   | 
     |     |   notify printB   |-----+   | 
     |     +-------------------+         | 
     |                                   | 
     |                                   | 
     |         +-----------+             | 
     +-------->|    wait   |             | 
               +-----------+             | 
                     |                   | 
                     V                   | 
              +-------------+            | 
              |    printB   |            | 
              +-------------+            | 
                     |                   | 
                     V                   | 
       N /-----------------------\       | 
     +---|   Get printA notify   |<--+   | 
     |   \-----------------------/   |   | 
     |               | Y             |   | 
     |               V               |   | 
     |       +---------------+       |   | 
     |       |   print "B"   |       |   | 
     |       +---------------+       |   | 
     |               |               |   | 
     |               V               |   | 
     |       +---------------+       |   | 
     |       |   isReady=2   |       |   | 
     |       +---------------+       |   | 
     |               |               |   | 
     |               V               |   | 
     |          +---------+          |   | 
     |          |   ++i   |          |   | 
     |          +---------+          |   | 
     |               |               |   | 
     |               V               |   | 
     |     +-------------------+     |   | 
     |     |   notify printC   |-----+   | 
     |     +-------------------+         | 
     |                                   | 
     |                                   | 
     |         +-----------+             | 
     +-------->|    wait   |             | 
               +-----------+             | 
                     |                   | 
                     V                   | 
              +-------------+            | 
              |    printC   |            | 
              +-------------+            | 
                     |                   | 
                     V                   | 
       N /-----------------------\       | 
     +---|   Get printB notify   |<--+   | 
     |   \-----------------------/   |   | 
     |               | Y             |   | 
     |               V               |   | 
     |       +---------------+       |   | 
     |       |   print "C"   |       |   | 
     |       +---------------+       |   | 
     |               |               |   | 
     |               V               |   | 
     |       +---------------+       |   | 
     |       |   isReady=0   |       |   | 
     |       +---------------+       |   | 
     |               |               |   | 
     |               V               |   | 
     |          +---------+          |   | 
     |          |   ++i   |          |   | 
     |          +---------+          |   | 
     |               |               |   | 
     |               V               |   | 
     |     +-------------------+     |   | 
     |     |   notify printA   |-----+   | 
     |     +-------------------+         | 
     |                                   | 
     |                                   | 
     |         +-----------+             | 
     +-------->|    wait   |             | 
               +-----------+             | 
                     |                   | 
                     V                   | 
                     O<------------------+ 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
std::mutex mtx;
std::condition_variable cv;
int i=1;
int isReady = 0;
const int n = 100;

void printA(){
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::unique_lock<std::mutex> lck(mtx); //unique_lock can auto unlock
    while(i<n){
        while(isReady !=0){
            cv.wait(lck); //isReady = 0 ia a signal to notify printA, so if isReady!0,A should be waiting 
        }
        cout << "A " ;
        isReady=1;
        if(i>=n){
            cv.notify_all();
            break;
        }        
        ++i;
        cv.notify_all();
    }
}

void printB(){
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::unique_lock<std::mutex> lck(mtx);
    while(i<n){
        while(isReady !=1){
            cv.wait(lck);
        }
        cout<<"B ";
        isReady=2;
        if(i>=n){
            cv.notify_all();
            break;
        }
        ++i;
        cv.notify_all();
    }
}

void printC(){
    std::this_thread::sleep_for(std::chrono::seconds(2));    
    std::unique_lock<std::mutex> lck(mtx);
    while(i<n){
        while(isReady !=2){
            cv.wait(lck);
        }
        cout<<"C ";
        isReady=0;
        if(i>=n){
            cv.notify_all();
            break;
        }
        ++i;
        cv.notify_all();
    }
}

int main(){

    thread A(printA);
    thread B(printB);
    thread C(printC);

    A.join();
    B.join();
    C.join();
    cout << endl << "i= " << i << endl;

    return 0;
}
Output:
A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B C A B 
i= 100

你可能感兴趣的:(数据结构,算法,c++,算法,数据结构,mutex,lock)