c++ 多线程笔记2

参考:https://baptiste-wicht.com/posts/2012/03/cp11-concurrency-tutorial-part-2-protect-shared-data.html

1.通常情况下,当你在多个线程之间使用共享对象时,需要解决同步的问题。(synchronization)

#include <iostream>
#include <thread>
#include <vector>
struct Counter 
{
    int value;
    Counter() : value(0){}
    
    void increment()
    {
        ++value;
    }
};

int main()
{
    Counter counter;

    std::vector< std::thread > threads;
    for(int i = 0; i < 5; ++i)
    {
        threads.push_back(std::thread([&counter](){
            for(int i = 0; i < 100; i++)
            {    
                counter.increment();
            }    
        }));
    }

    for(auto &thread : threads)
    {
        thread.join();
    }
    std::cout << counter.value << std::endl;
    return 0;
}

/***** my output: 500 ********/

上述代码并非原子操作(任意时刻只有一个线程对这个共享资源进行访问)。可能引入潜在的问题,交叉存取(interleave)引起的。

/*
*Thread 1 : read the value, get 0, add 1, so value = 1
*Thread 2 : read the value, get 0, add 1, so value = 1
*Thread 1 : write 1 to the field value and return 1
*Thread 2 : write 1 to the field value and return 1
*/

解决方法: Semaphores, Atomic reference, Monitors, Condition codes, Compare and swap, etc. 

本文主要介绍semaphore去解决该问题,实际使用的是一种特定种类的semaphore叫做mutexes.

一个mutex是一个非常简单的对象,只有一个线程可以获得一个互斥锁(the lock on the mutex at the same time)。

这个简单的特性可以让我们修正这个问题。

2.使用一个mutex确保我们的Counter 线程安全。

c++11库中mutex包含在mutex中,mutex类: std::mutex。有两个重要的方法:

mutex::lock() / unclock().lock()使一个线程获得这个锁,unclock()释放这个锁。

lock()能够实现阻塞。当lock已经被得到后线程从lock()返回。

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>

struct Counter 
{
    std::mutex mutex;
    int value;
    Counter() : value(0){}
    
    void increment()
    {
        mutex.lock();
        ++value;
        mutex.unlock();
    }
};

int main()
{
    Counter counter;

    std::vector< std::thread > threads;
    for(int i = 0; i < 5; ++i)
    {
        threads.push_back(std::thread([&counter](){
            for(int i = 0; i < 100; i++)
            {    
                counter.increment();
            }    
        }));
    }

    for(auto &thread : threads)
    {
        thread.join();
    }
    std::cout << counter.value << std::endl;
    return 0;
}
/*********** 能保证每次输出都为500**************/

3.Exceptions and locks

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

struct Counter
{
    int value;
    Counter() : value(0) {}

    void increment()
    {
        ++value;
    }

    void decrement()
    {
        if(value == 0)
        {
            throw "Value cannot be less than 0";
        }
        --value;
    }
}


struct ConcurrentCounter //wrapper
{
    std::mutex mutex;
    Counter counter;

    void increment()
    {
        mutex.lock();
        counter.increment();
        mutex.unlock();
    }
    
    void decrement()
    {
        mutex.lock();
        try {
            counter.decrement();
        } catch (std::string e) {
            mutex.unlock();
            throw e;
        }
        mutex.unclock();
    }
};

3. Automatic management of locks.

当想要保护代码的某块区域时,存在一个好的解决方案去避免忘记释放lock.

当创建std::lock_guard 后,它自动调用和释放互斥锁lock()。因此不需要2中例子处理lock() ,unlock().

struct ConcurrentSafeCounter {
    std::mutex mutex;
    Counter counter;

    void increment(){
        std::lock_guard<std::mutex> guard(mutex);
        counter.increment();
    }

    void decrement(){
        std::lock_guard<std::mutex> guard(mutex);
        counter.decrement();
    }
};

猜你喜欢

转载自www.cnblogs.com/Shinered/p/9079227.html