C++多線程編程二

1. 死鎖與解鎖:ios

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

using namespace std;

//thread引用類型函數,模板,避免類型轉換,儘可能指針,引用
//鎖住一個變量以後,儘快操做完解鎖,不要再鎖,不然互鎖
#define COUNT 100000
mutex g_mutex1, g_mutex2;//互斥量

void add1(int *p1, int *p2)
{
    for (int i = 0; i < COUNT; i++)
    {
        /*g_mutex1.lock();
        p1++;
        g_mutex2.lock();
        p2++;
        g_mutex1.unlock();
        g_mutex2.unlock();*/

        g_mutex1.lock();
        (*p1)++;
        g_mutex1.unlock();
        
        g_mutex2.lock();
        (*p2)++;
        g_mutex2.unlock();
    }
}
void add2(int *p1, int *p2)
{
    for (int i = 0; i < COUNT; i++)
    {
        /*g_mutex2.lock();
        g_mutex1.lock();
        p1++;
        g_mutex1.unlock();
        p2++;
        g_mutex2.unlock();*/

        g_mutex2.lock();
        (*p2)++;
        g_mutex2.unlock();

        g_mutex1.lock();
        (*p1)++;
        g_mutex1.unlock();
    }
}

void main()
{
    int a = 0;
    int b = 0;

    thread th1(add1, &a, &b);
    thread th2(add2, &a, &b);

    th1.join();
    th2.join();

    while (1)
    {
        cout << a << endl;
        cout << b << endl;
        this_thread::sleep_for(chrono::seconds(1));

    }

    cin.get();
}

 2. 迅雷面試題:面試

  編寫一個程序,開啓3個線程,這3個線程的ID分別爲A、B、C,每一個線程將本身的ID在屏幕上打印10遍,多線程

  要求輸出結果必須按ABC的順序顯示。如:ABCABC...,依次遞推。函數

    【參考答案】this

//編寫一個程序,開啓3個線程,這3個線程的ID分別爲A、B、C,每一個線程將本身的ID在屏幕上打印10遍,
//要求輸出結果必須按ABC的順序顯示。如:ABCABC...,依次遞推。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

int LOOP = 10;    //循環次數
int flag = 0;    //標識符 012012012012
mutex m;
condition_variable cv;

void fun(int id)
{
    for (int i = 0; i < LOOP; i++)
    {
        unique_lock<mutex> ulk(m);        //設定鎖定
        while ((id-65) != flag)
        {
            cv.wait(ulk);                //不是該出現的場合,就等待
        }
        cout << (char)id;                //轉換id

        flag = (flag + 1) % 3;            //012,012,012,...
        cv.notify_all();                //通知所有
    }
}

void main()
{
    thread t1(fun, 65);
    thread t2(fun, 66);
    thread t3(fun, 67);

    t1.join();
    t2.join();
    t3.join();

    cin.get();
}

    運行結果:spa

    【分析】若題目變爲:4個線程,輸出結果要求爲: ABCDABCDABCD...又該如何作呢?線程

//編寫一個程序,開啓3個線程,這3個線程的ID分別爲A、B、C,每一個線程將本身的ID在屏幕上打印10遍,
//要求輸出結果必須按ABC的順序顯示。如:ABCABC...,依次遞推。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

int LOOP = 10;    //循環次數
int flag = 0;    //標識符 012012012012
mutex m;
condition_variable cv;

void fun(int id)
{
    for (int i = 0; i < LOOP; i++)
    {
        unique_lock<mutex> ulk(m);        //設定鎖定
        while ((id-65) != flag)
        {
            cv.wait(ulk);                //不是該出現的場合,就等待
        }
        cout << (char)id;                //轉換id

        flag = (flag + 1) % 4;            //012,012,012,...
        cv.notify_all();                //通知所有
    }
}

void main()
{
    thread t1(fun, 65);
    thread t2(fun, 66);
    thread t3(fun, 67);
    thread t4(fun, 68);

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    cin.get();
}

    運行結果:指針

 3. 思考:上題中若變爲開啓5個線程,ID分別爲1,2,3,4,5,每一個線程將本身的ID在屏幕上打印10遍,要求輸出結果爲:12345,54321,12345,54321,...依此類推。code

 

 

4. 線程交換 swap:blog

#include <iostream>
#include <thread>
using namespace std;

void main()
{
    thread t1([]() {cout << "ZhangShan"<<endl; });
    thread t2([]() {cout << "LiSi"<<endl; });

    cout << "t1.get_id():" << t1.get_id() << "    t2.get_id():" << t2.get_id() << endl;

    swap(t1, t2);    //交換句柄

    cout << "t1.get_id():" << t1.get_id() << "    t2.get_id():" << t2.get_id() << endl;

    t1.join();
    t2.join();

    cin.get();
}

5. 線程移動 move:

#include <iostream>
#include <thread>
#include <cstdlib>

using namespace std;

void main()
{
    thread t1([]() 
    {
        int i = 0;
        while (1)
        {
            i++;
            if (i > 1000000000)
            {
                break;
            }
        }
        cout << i << endl;
        system("pause");
    });
    
    cout << "t1:" << t1.get_id() << endl;    //6872
    //t1.join();
    thread t2 = move(t1);//線程移動,t2具有了t1的屬性,t1掛了
    cout << "t1:" << t1.get_id() << endl;    //0
    cout << "t2:" << t2.get_id() << endl;    //6872

    t2.join();

    cin.get();
}

    運行結果:

 6. 線程自動加解鎖:

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

using namespace std;

#define N 10000000
mutex g_mutex;//全局互斥量

void add(int *p)
{
    for (int i = 0; i < N; i++)
    {
        unique_lock<mutex> ulk(g_mutex);
        //沒有mutex全部權,自動加鎖自動解鎖,根據塊語句鎖定
        //根據mutex屬性來決定,是否能夠加鎖

        //lock_guard<mutex> lgd(g_mutex);    
        //擁有mutex全部權,自動加鎖自動解鎖
        //讀取mutex失敗的狀況下就會一直等待
        (*p)++;
    }
}

void main()
{
    int a = 0;

    thread t1(add, &a);
    thread t2(add, &a);

    t1.join();
    t2.join();

    cout << a << endl;

    cin.get();
}

7. 線程等待固定時間:

#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <cstdlib>
#include <ctime>

using namespace std;

condition_variable cv;
mutex m;
bool done=false;

void run()
{
    auto start = chrono::high_resolution_clock::now();    //當前時間
    auto end = start + chrono::seconds(3);

    unique_lock<mutex> ulk(m);
    while (!done)
    {
        if (cv.wait_until(ulk, end) == cv_status::timeout)//超時
        {
            done = true;
            break;
        }
    }
    //this_thread::sleep_until(end);

    system("pause");
}

void main1601()
{
    thread th(run);

    cin.get();
}

void main()
{
    time_t t1, t2;
    auto start = chrono::high_resolution_clock::now();    //當前時間
    t1 = time(&t1);

    double db = 0;
    for (int i = 0; i < 1000000000; i++)
    {
        db += i;
    }

    auto end = chrono::high_resolution_clock::now();    //當前時間
    t2 = time(&t2);

    cout << (end - start).count() << endl;    //10^-9秒(ns)
    cout << difftime(t2, t1) << endl;

    cin.get();
}

 8. 多線程實現生產者、消費者:

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

using namespace std;

mutex m;
condition_variable isfull, isempty;//處理兩種狀況
bool flag = true;//標誌,消費完了就退出
vector<int> myint(10);//開闢10個元素

void produce(int num)    //生產
{
    for (int i = 0; i < num; i++)
    {
        unique_lock<mutex> lk(m);    //鎖定
        while (myint.size()>=10)
        {
            isempty.wait(lk);    //滿了一直等待
        }

        myint.push_back(i);//插入
        cout << "生產" << i << endl;
        isfull.notify_all();//通知消費者

    }

    this_thread::sleep_for(chrono::seconds(5));//休眠5秒

    flag = false;
}

void consume()    //消費
{
    while (flag)
    {
        unique_lock<mutex> lk(m);    //鎖定
        while (myint.size()==0)
        {
            isfull.wait(lk);//等待
        }
        
        if (flag)
        {
            cout << "消費" << myint[myint.size() - 1] << " " << this_thread::get_id() << endl;
            myint.pop_back();//剔除最後一個

            isempty.notify_all();//通知生產者繼續生產
        }
    }
}

void main()
{
    thread t1(consume);    //消費者
    thread t2(consume);
    thread t3(consume);

    //produce(100);
    thread s1(produce,15);//消費者
    thread s2(produce,15);

    t1.join();
    t2.join();
    t3.join();

    cin.get();
}
相關文章
相關標籤/搜索