C++11 線程管理

1 線程啟動(dòng)
2 參數(shù)傳遞
  2.1 參數(shù)傳遞
  2.2 引用傳參
3 線程所有權(quán)管理
4 線程標(biāo)志

1 線程啟動(dòng)

std::thread構(gòu)造函數(shù)接受可調(diào)用對(duì)象啟動(dòng)線程,如下所示:

#include <iostream>
#include <thread>
#include <string>
#include <functional>

void f(int i) {
    std::cout << "Func, i=" << i << "\n";
}

struct Foo {
    void operator()(int i) {
        std::cout << "Class Function Call Object, i=" << i << "\n";
    }
};

struct Foo2 {
    void func(int i) {
        std::cout << "Class Method, i=" << i << "\n";
    }
};

int main() {
    // by normal function
    std::thread t1(f, 1);
    t1.join();

    // by class operator()
    Foo foo;
    std::thread t2(foo, 2);
    t2.join();

    //by lamda
    int i = 3;
    std::thread t3([i]() {
        std::cout << "Lamda, i=" << i << "\n";
    });
    t3.join();

    // by member function
    Foo2 foo2;
    auto f3 = std::mem_fn(&Foo2::func);
    std::thread t4(f3, foo2, 4);
    t4.join();

    // by bind
    auto f1 = std::bind(f, std::placeholders::_1);
    std::thread t5(f1, 5);
    t5.join();

    // by std::function
    std::function<void(int)> f2 = f;
    std::thread t6(f2, 6);
    t6.join();
}

假設(shè)文件名為thread.cpp, 則編譯命令為:
g++ -std=c++11 -lpthread thread.cpp -o test_thread
執(zhí)行./test_thread后程序輸出為

Func, i=1
Class Function Call Object, i=2
Lamda, i=3
Class Method, i=4
Func, i=5
Func, i=6

2 參數(shù)傳遞

2.1 基本范例

下面例子是一個(gè)向線程傳遞參數(shù)的示例

#include <iostream>
#include <thread>
#include <string>
void f(int i, const std::string& s) {
    std::cout << "i = " << i << "\n"
        << "s = " << s << std::endl;
}

int main() {
    char buffer[1024];
    sprintf(buffer, "%i", 1234);
    std::thread t(f, 3, buffer);
    t.detach();
}

這個(gè)程序存在一個(gè)隱患, 由于主進(jìn)程detach了,所以buffer在轉(zhuǎn)成std::string之前有可能因?yàn)橹鬟M(jìn)程退出而銷毀,正確的方式是在主進(jìn)程中就把buffer轉(zhuǎn)成std::string, 如下

// std::thread t(f, 3, buffer);  =>
std::thread t(f, 3, std::string(buffer));

2.2 引用傳參

C++11 支持使用std::ref向線程按照引用方式傳遞參數(shù), 如下范例:

#include <iostream>
#include <thread>
#include <string>

void func(int& i, std::string& s) {
    ++i;
    s = "update value";
}

int main() {
    int i = 0;
    std::string s("old value");
    std::thread t(func, std::ref(i), std::ref(s));
    t.join();

    std::cout << "i=" << i << "\n"
        << "s=" << s << std::endl;
    return 0;
}

程序輸出結(jié)果為:

i=1
s=update value

3 線程所有權(quán)管理

std::thread都是可移動(dòng),但不可拷貝, 如下面示例:

#include <iostream>
#include <thread>

void f(int i) {
    std::cout << "Func, i=" << i << "\n";
}

std::thread gen_a_thread() {
    std::thread t(f, 2);
    return t;
}

int main() {
    std::thread t1(f, 1);

    //std::thread t2 = t1;  this is not allowed

    // transfer ownership, call move constructor
    std::thread t2 = std::move(t1);
    t2.join();

    // transfer ownership, call move constructor
    std::thread t3 = gen_a_thread();
    t3.join();
}

輸出為:

Func, i=1
Func, i=2

對(duì)于需要join的線程,為了確保join一定會(huì)被調(diào)用,可以創(chuàng)建下面的thread_scope類,如下:

#include <iostream>
#include <thread>
#include <exception>

void f(int i) {
    std::cout << "Func, i=" << i << "\n";
}

class ThreadScope {
public:
    explicit ThreadScope(std::thread t): _t(std::move(t)) {
        if (!_t.joinable()) {
            throw std::logic_error("no thread");
        }
    }

    ~ThreadScope() {
        _t.join();
    }

    //disallow copy and assign
    ThreadScope(const ThreadScope& t) = delete;
    ThreadScope& operator=(const ThreadScope& t) = delete;

private:
    std::thread _t;
};


int main() {
    ThreadScope ts(std::thread(f, 1));
}

可以將std::thread放入std::vector中,批量創(chuàng)建線程并且等待它們結(jié)束,示例如下:

#include <iostream>
#include <thread>
#include <vector>
#include <sstream>
#include <algorithm>

void worker(int i) {
    std::stringstream ss;
    ss << "worker_";
    ss << i;
    ss << "\n";
    std::cout << ss.str();
}

int main() {
    const size_t WORKER_NUM = 20;
    std::vector<std::thread> threads;
    for (auto i = 0; i < WORKER_NUM; ++i) {
        threads.emplace_back(std::thread(worker, i));
    }

    std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
}

4 線程標(biāo)志

線程標(biāo)識(shí)類型是std::thread::id,可以通過(guò)兩種方式進(jìn)行檢索。第一種,可以通過(guò)調(diào)用std::thread對(duì)象的成員函數(shù)get_id()來(lái)直接獲取。如果std::thread對(duì)象沒有與任何執(zhí)行線程相關(guān)聯(lián),get_id()將返回std::thread::type默認(rèn)構(gòu)造值,這個(gè)值表示“沒有線程”。第二種,當(dāng)前線程中調(diào)用std::this_thread::get_id()。 示例代碼如下:

#include <iostream>
#include <thread>
#include <vector>
#include <sstream>
#include <algorithm>

void worker(int i) {
    std::stringstream ss;
    ss << std::this_thread::get_id() << "\n";
    std::cout << ss.str();
}

int main() {
    const size_t WORKER_NUM = 5;
    std::vector<std::thread> threads;
    for (auto i = 0; i < WORKER_NUM; ++i) {
        threads.emplace_back(std::thread(worker, i));
    }

    std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
}

輸出如下:

139865582319360
139865571829504
139865561339648
139865540359936
139865550849792
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容