C++多線程編程一

1.C++多線程初步:ios

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

void run()
{
    MessageBoxA(0, "hello world", "hello china", 0);

}

void main0101()
{
    //同步(阻塞)
    run();
    run();
    run();

    cin.get();
}

void main0102()
{
    //並行,異步,非阻塞
    thread t1(run);        //根據函數初始化並執行,t1在棧上
    thread t2(run);
    thread t3(run);
    thread t4(run);

    cin.get();
}

void main0103()
{
    //並行,異步,非阻塞
    //thread t[5]{ run,run,run,run,run };    //error C2440: 「初始化」: 沒法從「void (__cdecl *)(void)」轉換爲「std::thread」
    thread t[5]{ thread(run),thread(run), thread(run), thread(run), thread(run) };    //初始化線程數組(線程池)

    cin.get();
}

void main0104()
{
    //堆上
    thread *pthread1(new thread(run));
    thread *pthread2(new thread(run));
    thread *pthread3(new thread(run));
    
    cin.get();
}

void main()
{
    //堆上開闢了線程數組
    thread *pthread1(new thread[5]{ thread(run),thread(run), thread(run), thread(run), thread(run) });

    cin.get();
}

2. 線程凍結與解凍調試:數組

#include <iostream>
#include <thread>
#include <Windows.h>
#include <cstdlib>

using namespace std;

void test()
{
    int i = 0;
    while (1)
    {
        cout << ++i << endl;
        Sleep(1000);
    }
}

void main()
{
    thread *p(new thread(test));    //堆上

    system("pause");

    system("pause");

    system("pause");

    system("pause");

    cin.get();
}

3. 多線程傳參:promise

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

void showmsg(const char *str1, const char *str2)
{
    MessageBoxA(0, str1, str2, 0);
}

void main()
{
    thread th1(showmsg, "1", "1");
    thread th2(showmsg, "111", "111");
    thread th3(showmsg, "222", "222");
    cin.get();
}

4. 多線程的join 和detach:安全

#include <iostream>
#include <thread>
#include <array>
#include <Windows.h>

using namespace std;

//join讓當前主線程等待全部子線程執行完成才能退出
//detach脫離主線程的綁定,主線程退出的時候,不影響子線程。
void show()
{
    MessageBoxA(0, "1", "1", 0);
}

void main0401()
{
    array<thread, 3> threads{ thread(show),thread(show),thread(show) };

    for (int i = 0; i < 3; i++)
    {
        cout << threads[i].joinable() << endl;    //判斷是否能夠join 
        threads[i].join();    //主線程等待子線程執行完成再退出 
    }

    auto n = thread::hardware_concurrency();    //獲取CPU是幾核
    cout << n << endl;

    cin.get();
}

void main()
{
    thread th(show);
    //th.join();
    th.detach();    //脫離主線程,主線程掛了不報錯
    //detach之後線程沒法通訊

    th.joinable();
}

5. 原子變量與線程安全:多線程

#include <iostream>
#include <thread>
#include <mutex>    //互斥量
#include <atomic>    //原子變量

using namespace std;

//線程安全,多線程訪問不衝突就是線程安全,衝突則不安全
//int num = 0;

//mutex m;    //互斥,加鎖解鎖浪費時間

atomic_int num(0);    //原子變量不會發生線程衝突,屬於線程安全

void run()
{
    for (int i = 0; i < 10000000; i++)
    {
        //m.lock();
        num++;
        //m.unlock();
    }
}

void main()
{
    clock_t start = clock();

    thread th1(run);
    thread th2(run);
    th1.join();
    th2.join();

    clock_t end = clock();
    cout << num << endl;
    cout << end - start << "ms" << endl;
     
    cin.get();
}
//全局變量,會發生衝突,結果不正確,速度快
//mutex,結果正確,速度慢
//atomic,結果正確,速度比mutex快

6. lambda 表達式與多線程:異步

#include <iostream>
#include <thread>
#include <Windows.h>
#include <chrono>

using namespace std;

void main0701()
{
    //auto fun = []() {MessageBoxA(0, "1", "2", 0); };
    //thread th1(fun);
    //thread th2(fun);

    thread th1([]() {MessageBoxA(0, "11", "22", 0); });
    thread th2([]() {MessageBoxA(0, "11", "22", 0); });

    cin.get();
}

void main()
{
    //thread th1([]() {cout << this_thread::get_id() << endl; });    //獲取當前線程的id
    //thread th2([]() {cout << this_thread::get_id() << endl; });

    thread th1([]() {
        this_thread::sleep_for(chrono::seconds(3));    //等待3秒
        this_thread::yield();        //讓CPU先執行其餘線程,空閒了再執行我
        cout << this_thread::get_id() << endl;        //獲取當前線程的id
        //this_thread::sleep_until();    //某個時刻到來以前一直等待
    });
    thread th2([]() {
        this_thread::sleep_for(chrono::seconds(10));    //等待10秒
        cout << this_thread::get_id() << endl;
    });

    cin.get();
}

 7. 僞函數與多線程:async

  (1)僞函數概念:函數

#include <iostream>
using namespace std;

struct func
{
    void operator ()()    //僞函數,能夠將對象名當作函數名來使用
    {
        cout << "hello china hello cpp" << endl;
    }

    void operator ()(int i)    //僞函數,能夠將對象名當作函數名來使用
    {
        cout << "hello china hello cpp! " << i << endl;
    }
};

void main()
{
    func f1;
    f1();

    func f2;
    f2(2);

    cin.get();
}

  (2)僞函數與多線程:this

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

struct MyStruct
{
    MyStruct()
    {
        cout << "create" << endl;
    }
    ~MyStruct()
    {
        cout << "end" << endl;
    }

    void operator ()()    //對象名當作函數名使用,重載了(),但()只適用於當前結構體對象
    {
        MessageBoxA(0, "111", "222", 0);
    
    }
};

void main()
{
    MyStruct go1;
    thread t1(go1);

    MyStruct go2;
    thread t2(go2);

    //MyStruct()是構造函數,建立一個臨時對象,匿名對象
    //MyStruct()();
    //thread t3(MyStruct());//匿名的對象,不適合做爲多線程參數,銷燬太快

    //MyStruct *p = new MyStruct;
    MyStruct *p = new MyStruct();//多一個()就是構造函數

    cin.get();
}

8. 成員函數構建多線程:atom

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

struct fun
{
    void run1()
    {
        MessageBoxA(0, "12345", "ABCDE", 0);
        cout << "hello china" << endl;
    }

    void run2(const char *str)
    {
        MessageBoxA(0, str, str, 0);
        cout << "hello china" << endl;
    }
};

void main()
{
    //fun *p(nullptr);
    //p->run1();            //空類指針能夠引用沒有調用內部變量的成員函數

    fun fun1;
    //&fun::run引用成員函數
    thread th1(&fun::run1, fun1);
    thread th2(&fun::run1, fun1);

    thread th3(&fun::run2, fun1,"run2-1");
    thread th4(&fun::run2, fun1, "run2-2");

    cin.get();
}

9. 多線程通訊future:

#include <iostream>
#include <thread>
#include <future>
#include <string>
#include <cstdlib>

using namespace std;

void main0401()
{
    string str1("12345");
    string str2("678910");
    string str3(str1 + str2);    //C++風格的字符串
    cout << str3 << endl;

    cin.get();
}

promise<string>val;    //全局通訊變量

void main()
{
    thread th1([]() 
    {
        future<string> fu = val.get_future();//獲取將來的狀態
        cout << "等待中..." << endl;
        cout << fu.get() << endl;
    });


    thread th2([]() 
    {
        system("pause");
        val.set_value("I love CPP");
        system("pause");
    }); 

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

}

10. 基於繼承的多線程:

#include <iostream>
#include <thread>

using namespace std;

class zhangthread :public thread //C++代碼重用-->繼承
{
public:
    zhangthread() :thread()    //子類調父類的構造函數
    {
        
    }

    template <typename T, typename...Args>    //子類調父類的構造函數,可變參數的構造
    zhangthread(T && func,Args &&...args):thread(   forward<T>(func),    forward<Args>(args)...   )
    {
        
    }

    void run(const char *cmd)    //新增的功能
    {
        system(cmd);
    }
};

void main()
{
    zhangthread t1([](){cout << "hello this is Zhang"<<endl;});
    t1.run("calc");

    zhangthread t2([](int num)    {cout << "hello this is Zhang"<<num<<endl; },100   );
    t2.run("notepad");

    cin.get();
}

11. 條件變量:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>    //條件變量

using namespace std;

//線程通訊,結合mutex
//一個線程,多個線程處於等待,通知一個或通知多個

mutex m;                //線程互相排斥
condition_variable cv;    //線程通訊

void main()
{
    thread **th = new thread * [10];//開闢線程的指針數組

    for (int i = 0; i < 10; i++)
    {
        th[i] = new thread([](int index) 
        {
            unique_lock<mutex> lck(m);    //鎖定
            cv.wait_for(lck, chrono::hours(1000));    //一直等待
            cout << index << endl;        //打印編號
        }  ,   i );    //傳遞參數

        this_thread::sleep_for(chrono::milliseconds(100));    //錯開
    }

    for (int i = 0; i < 10; i++)
    {
        lock_guard<mutex> lckg(m);//解鎖嚮導
        cv.notify_one();    //挨個通知
    }

    for (int i = 0; i < 10; i++)
    {
        th[i]->join();
        delete th[i];
    }

    delete[]th;    //釋放指針數組

    cin.get();
}

12. 獲取線程的結果:

#include <iostream>
#include <thread>
#include <future>//線程未來結果
#include <chrono>//時間
#include <mutex>

using namespace std;

mutex g_m;

void main()
{
    auto run = [=](int index)->int 
    {
        lock_guard<mutex> lckg(g_m);    //加鎖
        cout << this_thread::get_id() << " " << index << endl;    //獲取線程id
        this_thread::sleep_for(chrono::seconds(10));    //等待10秒
        return index * 1024;    //返回結果
    };

    packaged_task<int(int)> pt1(run);
    packaged_task<int(int)> pt2(run);    //建立兩個任務包

    thread t1([&]() {pt1(2); });
    thread t2([&]() {pt2(3); });    //開啓線程

    cout << pt1.get_future().get() << endl;
    cout << pt2.get_future().get() << endl;    //獲取結果

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


    cin.get();
}

 13. 可變參數實現多線程:

#include <iostream>
#include <cstdarg>
#include <thread>

using namespace std;

//可變參數
int go(const char *fmt, ...)
{
    va_list ap;            //第一個數據(指針)
    va_start(ap, fmt);    //開始

    vprintf(fmt, ap);    //調用

    va_end(ap);            //結束

    return 0;
}

void main()
{
    thread th(go, "%sABCD%d____%c____%x", "12345abc", 123, 'A', 256);

    cin.get();
}

14. 多線程實現並行計算:

#include <iostream>
#include <thread>
#include <future>
#include <vector>
#include <cstdlib>

using namespace std;

#define COUNT 1000000

//線程函數:
int add(vector<int> *arr, int start, int count)
{
    static mutex m;    //靜態局部變量,只會初始化一次
    int sum(0);//保存結果

    for (int i = 0; i < count; i++)
    {
        sum += (*arr)[start + i];//實現累加
    }

    {    //此處僅僅是計算過程當中的顯示,更清楚查看
        lock_guard<mutex> lckg(m);//加鎖,不讓其餘線程干涉

        cout << "thread" << this_thread::get_id() << ",count=" << count << ",sum=" << sum << endl;
    }

    return sum;
}

void main()
{
    vector<int> data(COUNT);    //數組,100萬的大小
    for (int i = 0; i < COUNT; i++)
    {
        data[i] = i % 1000;    //0-999
    }

    vector< future<int> > result;//結果數組

    int cpus = thread::hardware_concurrency();//CPU核心的個數

    for (int i = 0; i < cpus * 2; i++)
    {
        //1000 10= 100 * 10
        //1000 9 = 1000 - 111*8
        int batch_each = COUNT / (cpus * 2);

        if (i == (cpus * 2) - 1)
        {
            batch_each = COUNT - COUNT / (cpus * 2)*i;//最後一個承擔的多一點
        }

        //不斷壓入結果
        result.push_back(async(add, &data, i*batch_each, batch_each));//async直接返回結果

    }

    //彙總
    int lastresult(0);
    for (int i = 0; i < cpus * 2; i++)
    {
        lastresult += result[i].get();//彙總結果,累加
    }
    cout << "lastresule=" << lastresult << endl;

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