1. 遇到的问题

#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <cmath> 
#include <vector>
#include <cstdlib>
using namespace std; 

class Counter 
{
public:
    void addCount() {
        m_count++;
    }
    int count() const { return m_count; }
    Counter() : m_count(0) {    }
private:
    int m_count;
};

int work(int a)
{
    return a + a;
}

template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
    for (; b != e; ++b)
    {
        totalValue += work(*b);
        c.addCount();
    }
}

int main()
{
    unsigned n = std::thread::hardware_concurrency();
    cout << n << " concurrent threads are support.\n";
    
    vector<int> vec;
    double totalValue = 0;
    for (int i = 0; i < 10000000; i++)
    {
        vec.push_back(rand() % 100);
    }
    Counter counter;
    realWork(counter, totalValue, vec.begin(), vec.end());
    cout << "total times: " << counter.count() << " " << totalValue << endl;


    totalValue = 0;
    Counter counter2;
    auto iter = vec.begin() + (vec.size() / 3);
    auto iter2 = vec.begin() + (vec.size() / 3 * 2);
    thread b([&counter2, &totalValue, iter, iter2](){
        realWork(counter2, totalValue, iter, iter2);
    });
    auto end = vec.end();
    thread c([&counter2, &totalValue, iter2, end](){
        realWork(counter2, totalValue, iter2, end);
    });

    realWork(counter2, totalValue, vec.begin(), iter);

    b.join();
    c.join();
    cout << "total times use multithread: " << counter2.count() << " " << totalValue << endl; 

    return 0;
}

深入学习c++--多线程编程(二)【当线程间需要共享非const资源】

计算结果不一致!三个线程共享一份资源,有的加了有的没加。

2. 解决

2.1 法一:不共享变量

#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <cmath> 
#include <vector>
#include <cstdlib>
using namespace std; 

class Counter 
{
public:
    void addCount() {
        m_count++;
    }
    int count() const { return m_count; }
    Counter() : m_count(0) {    }
private:
    int m_count;
};

int work(int a)
{
    return a + a;
}

template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
    for (; b != e; ++b)
    {
        totalValue += work(*b);
        c.addCount();
    }
}

int main()
{
    unsigned n = std::thread::hardware_concurrency();
    cout << n << " concurrent threads are support.\n";
    
    vector<int> vec;
    double totalValue = 0;
    for (int i = 0; i < 10000000; i++)
    {
        vec.push_back(rand() % 100);
    }
    Counter counter;
    realWork(counter, totalValue, vec.begin(), vec.end());
    cout << "total times: " << counter.count() << " " << totalValue << endl;


    totalValue = 0;
    Counter counter2;
    auto iter = vec.begin() + (vec.size() / 3);
    auto iter2 = vec.begin() + (vec.size() / 3 * 2);
    double totalC = 0;
    thread b([&counter2, &totalValue, iter, iter2](){
        realWork(counter2, totalValue, iter, iter2);
    });
    auto end = vec.end();
    thread c([&counter2, &totalC, iter2, end](){
        realWork(counter2, totalC, iter2, end);
    });

    double totalD = 0;
    realWork(counter2, totalD, vec.begin(), iter);

    b.join();
    c.join();
    cout << "total times use multithread: " << counter2.count() << " " << totalValue+totalC+totalD << endl; 

    return 0;
}

深入学习c++--多线程编程(二)【当线程间需要共享非const资源】

2.2 法二:原子操作变量类型(复杂,适合简单应用)

b,c 线程共享了变量 counter2, 没有共享变量 totalValue,所以totalValue一样,counter2.count()不一样 

count++: 写入寄存器,寄存器+1,写入内存

average()函数功能是如果Counter2不等于10000000,程序就不退出,如运行截图,由于共享变量counter2, 导致counter2总是无法等于10000000

#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <cmath> 
#include <vector>
#include <cstdlib>
#include <string>
using namespace std; 

class Counter 
{
public:
    void addCount() {
        m_count++;
    }
    int count() const { return m_count; }
    Counter() : m_count(0) {    }
private:
    int m_count;
};

int work(int a)
{
    return a + a;
}

template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
    for (; b != e; ++b)
    {
        totalValue += work(*b);
        c.addCount();
    }
}

void printAll(int a, int b, int c)
{
    cout << a << " " << b << " " << c << endl;
}

void add(int a, int b, int& c)
{
    c = a + b;
}

void printString(const string& info, const string& info2)
{
    cout << "hello " << info << " " << info2 << endl;
}

void testThreadInit()
{
    int a = 3;
    int b = 4;
    int c = 5;
    thread t([=](){
        printAll(a, b, c);
    });
    t.join();

    thread t2(printAll, a, b, c);
    t2.join();

    thread t3([=, &c](){
        add(a, b, c);
    });
    t3.join();
    cout << "after add: " << c << endl;

    // c是引用, 必须用 ref(c)
    c = 0;
    thread t4(add, a, b, std::ref(c));
    t4.join();
    cout << "after add: " << c << endl;

    string abc("abc");
    string def("def");

    thread t5([&](){
        printString(abc, def);
    });
    t5.join();

    // 效率比引用低
    thread t6(printString, abc, def);
    t6.join();

    // cref: 常引用
    thread t7(printString, cref(abc), cref(def));
    t7.join();

}

bool average(Counter& c, int maxCount)
{
    auto cnt = c.count();
    if (cnt == maxCount) {
        cout << " ok finished \n";
        return true;
    }
    return false;
}

int main()
{
    testThreadInit();

    // (1) 如果没有必要的话,线程间不要共享资源
    unsigned n = std::thread::hardware_concurrency();
    cout << n << " concurrent threads are support.\n";
    
    vector<int> vec;
    double totalValue = 0;
    for (int i = 0; i < 10000000; i++)
    {
        vec.push_back(rand() % 100);
    }
    Counter counter;
    realWork(counter, totalValue, vec.begin(), vec.end());
    cout << "total times: " << counter.count() << " " << totalValue << endl;


    totalValue = 0;
    Counter counter2;
    thread printCount([&counter2](){
        while (!average(counter2, 10000000)) {
        }            
    });
    auto iter = vec.begin() + (vec.size() / 3);
    auto iter2 = vec.begin() + (vec.size() / 3 * 2);
    double totalC = 0;
    //b,c 线程共享了变量 counter2, 没有共享变量 totalValue,所以totalValue一样,counter2.count()不一样 
    thread b([&counter2, &totalValue, iter, iter2](){
        realWork(counter2, totalValue, iter, iter2);
    });
    auto end = vec.end();
    thread c([&counter2, &totalC, iter2, end](){
        realWork(counter2, totalC, iter2, end);
    });

    double totalD = 0;
    realWork(counter2, totalD, vec.begin(), iter);
    b.join();
    c.join();
    
    auto realTotalCount = counter2.count();
    
    totalValue += totalC + totalD;
    cout << "total times use multithread: " << realTotalCount << " " << totalValue << endl; 
    
    printCount.join();
    // (2) 


    return 0;
}

深入学习c++--多线程编程(二)【当线程间需要共享非const资源】

解决:原子操作变量

只需要把int m_count; 改成 atomic<int> m_count; 即可

#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <atomic>
#include <cmath> 
#include <vector>
#include <cstdlib>
#include <string>
using namespace std; 

class Counter 
{
public:
    void addCount() {
        m_count++;
    }
    int count() const { return m_count; }
    Counter() : m_count(0) {    }
private:
//    atomic_int m_count;
    atomic<int> m_count;

};

int work(int a)
{
    return a + a;
}

template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
    for (; b != e; ++b)
    {
        totalValue += work(*b);
        c.addCount();
    }
}

bool average(Counter& c, int maxCount)
{
    auto cnt = c.count();
    if (cnt == maxCount) {
        cout << " ok finished \n";
        return true;
    }
    return false;
}

int main()
{
    // (1) 如果没有必要的话,线程间不要共享资源
    unsigned n = std::thread::hardware_concurrency();
    cout << n << " concurrent threads are support.\n";
    
    vector<int> vec;
    double totalValue = 0;
    for (int i = 0; i < 10000000; i++)
    {
        vec.push_back(rand() % 100);
    }
    Counter counter;
    realWork(counter, totalValue, vec.begin(), vec.end());
    cout << "total times: " << counter.count() << " " << totalValue << endl;


    totalValue = 0;
    Counter counter2;
    thread printCount([&counter2](){
        while (!average(counter2, 10000000)) {
        }            
    });
    auto iter = vec.begin() + (vec.size() / 3);
    auto iter2 = vec.begin() + (vec.size() / 3 * 2);
    double totalC = 0;
    //b,c 线程共享了变量 counter2, 没有共享变量 totalValue,所以totalValue一样,counter2.count()不一样 
    thread b([&counter2, &totalValue, iter, iter2](){
        realWork(counter2, totalValue, iter, iter2);
    });
    auto end = vec.end();
    thread c([&counter2, &totalC, iter2, end](){
        realWork(counter2, totalC, iter2, end);
    });

    double totalD = 0;
    realWork(counter2, totalD, vec.begin(), iter);
    b.join();
    c.join();
    
    auto realTotalCount = counter2.count();
    
    totalValue += totalC + totalD;
    cout << "total times use multithread: " << realTotalCount << " " << totalValue << endl; 
    
    printCount.join();

    return 0;
}

深入学习c++--多线程编程(二)【当线程间需要共享非const资源】

 3. 新需求

两个变量,其中第一个变量变化,另一个还没来得及变化,另一个线程又变化了第一个变量

深入学习c++--多线程编程(二)【当线程间需要共享非const资源】

4. 解决:临界区--mutex

核心:

void lockMutex() { m_mutex.lock(); }
void unlockMutex() { m_mutex.unlock(); }


c.lockMutex();
c.addCount();
c.addResource(1);
c.unlockMutex();

完整代码:(不是非常好的写法)

#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <atomic>
#include <cmath> 
#include <vector>
#include <cstdlib>
#include <string>
#include <mutex>
using namespace std; 

class Counter 
{
public:
    void addCount() {
        m_count++;
    }
    int count() const { return m_count; }
    Counter() : m_count(0) {    }
    void addResource(int a) {
        m_totalResource++;
    }
    int aveResource() { 
        if (m_count == 0) 
            return 1;
        return m_totalResource / m_count; 
    }
    void lockMutex() { m_mutex.lock(); }
    void unlockMutex() { m_mutex.unlock(); }

private:
//    atomic_int m_count;
    atomic<int> m_count;
    atomic<int> m_totalResource;
    mutex m_mutex;
};

int work(int a)
{
    return a + a;
}

template<class Iter>
void realWork(Counter& c, double &totalValue, Iter b, Iter e)
{
    for (; b != e; ++b)
    {
        totalValue += work(*b);
        
        c.lockMutex();

        c.addCount();
        c.addResource(1);

        c.unlockMutex();
    }
}

bool average(Counter& c, int maxCount)
{
    auto cnt = c.count();

    c.lockMutex();
    auto ave = c.aveResource();
    if (ave != 1) cout << "has bad thing happened\n";
    c.unlockMutex();

    if (cnt == maxCount) {
        cout << " ok finished \n";
        return true;
    }
    return false;
}

int main()
{
    // (1) 如果没有必要的话,线程间不要共享资源
    unsigned n = std::thread::hardware_concurrency();
    cout << n << " concurrent threads are support.\n";
    
    vector<int> vec;
    double totalValue = 0;
    for (int i = 0; i < 10000000; i++)
    {
        vec.push_back(rand() % 100);
    }
    Counter counter;
    realWork(counter, totalValue, vec.begin(), vec.end());
    cout << "total times: " << counter.count() << " " << totalValue << endl;


    totalValue = 0;
    Counter counter2;
    thread printCount([&counter2](){
        while (!average(counter2, 10000000)) {
        }            
    });
    auto iter = vec.begin() + (vec.size() / 3);
    auto iter2 = vec.begin() + (vec.size() / 3 * 2);
    double totalC = 0;
    //b,c 线程共享了变量 counter2, 没有共享变量 totalValue,所以totalValue一样,counter2.count()不一样 
    thread b([&counter2, &totalValue, iter, iter2](){
        realWork(counter2, totalValue, iter, iter2);
    });
    auto end = vec.end();
    thread c([&counter2, &totalC, iter2, end](){
        realWork(counter2, totalC, iter2, end);
    });

    double totalD = 0;
    realWork(counter2, totalD, vec.begin(), iter);
    b.join();
    c.join();
    
    auto realTotalCount = counter2.count();
    
    totalValue += totalC + totalD;
    cout << "total times use multithread: " << realTotalCount << " " << totalValue << endl; 
    
    printCount.join();

    return 0;
}

深入学习c++--多线程编程(二)【当线程间需要共享非const资源】

注意:使用临界区,可能会发生死锁

 

 

相关文章:

  • 2022-12-23
  • 2022-02-18
  • 2021-08-18
  • 2022-01-21
  • 2022-01-15
  • 2022-12-23
  • 2021-11-20
  • 2021-12-25
猜你喜欢
  • 2021-08-25
  • 2021-09-29
  • 2022-12-23
  • 2021-08-30
  • 2022-02-12
  • 2022-12-23
相关资源
相似解决方案