C++11 多线程(std::thread)实例

C++11的std::thread
在C中已经有一个叫做pthread的东西来进行多线程编程,但是并不好用 (如果你认为句柄、回调式编程很实用,那请当我没说),所以c++11标准库中出现了一个叫作std::thread的东西。

std::thread常用成员函数
构造&析构函数

举个栗子

例一:thread的基本使用

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 using namespace std;
 6 void doit() { cout << "World!" << endl; }
 7 int main() {
 8     // 这里的线程a使用了 C++11标准新增的lambda函数
 9     // 有关lambda的语法,请参考我之前的一篇博客
10     // https://blog.csdn.net/sjc_0910/article/details/109230162
11     thread a([]{
12         cout << "Hello, " << flush;
13     }), b(doit);
14     a.join();
15     b.join();
16     return 0;
17 }

那么,为什么会有不同的结果呢?
这就是多线程的特色!

多线程运行时是以异步方式执行的,与我们平时写的同步方式不同。异步方式可以同时执行多条语句。

在上面的例子中,我们定义了2个thread,这2个thread在执行时并不会按照一定的顺序。打个比方,2个thread执行时,就好比赛跑,谁先跑到终点,谁就先执行完毕。

例二:thread执行有参数的函数
 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 using namespace std;
 6 void countnumber(int id, unsigned int n) {
 7     for (unsigned int i = 1; i <= n; i++);
 8     cout << "Thread " << id << " finished!" << endl;
 9 }
10 int main() {
11     thread th[10];
12     for (int i = 0; i < 10; i++)
13         th[i] = thread(countnumber, i, 100000000);
14     for (int i = 0; i < 10; i++)
15         th[i].join();
16     return 0;
17 }

 

注意:我说的是有可能。你的运行结果可能和我的不一样,这是正常现象,在上一个例子中我们分析过原因。

这个例子中我们在创建线程时向函数传递了一些参数,但如果要传递引用参数呢?是不是像这个例子中直接传递就行了?

让我们来看看第三个例子:

例三:thread执行带有引用参数的函数
 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 using namespace std;
 6 template<class T> void changevalue(T &x, T val) {
 7     x = val;
 8 }
 9 int main() {
10     thread th[100];
11     int nums[100];
12     for (int i = 0; i < 100; i++)
13         th[i] = thread(changevalue<int>, nums[i], i+1);
14     for (int i = 0; i < 100; i++) {
15         th[i].join();
16         cout << nums[i] << endl;
17     }
18     return 0;
19 }

如果你尝试编译这个程序,那你的编译器一定会报错

 这是怎么回事呢?原来thread在传递参数时,是以右值传递的:

// Compiler: MSVC 19.29.30038.1
// C++ Standard: C++17
#include <iostream>
#include <thread>
using namespace std;
template<class T> void changevalue(T &x, T val) {
    x = val;
}
int main() {
    thread th[100];
    int nums[100];
    for (int i = 0; i < 100; i++)
        th[i] = thread(changevalue<int>, ref(nums[i]), i+1);
    for (int i = 0; i < 100; i++) {
        th[i].join();
        cout << nums[i] << endl;
    }
    return 0;
}

这次编译可以成功通过,你的程序输出的结果应该是这样的:

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 using namespace std;
 6 int n = 0;
 7 void count10000() {
 8     for (int i = 1; i <= 10000; i++)
 9         n++;
10 }
11 int main() {
12     thread th[100];
13     // 这里偷了一下懒,用了c++11的foreach结构
14     for (thread &x : th)
15         x = thread(count10000);
16     for (thread &x : th)
17         x.join();
18     cout << n << endl;
19     return 0;
20 }

例四:std::mutex的使用

// Compiler: MSVC 19.29.30038.1
// C++ Standard: C++17
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int n = 0;
mutex mtx;
void count10000() {
    for (int i = 1; i <= 10000; i++) {
        mtx.lock();
        n++;
        mtx.unlock();
    }
}
int main() {
    thread th[100];
    for (thread &x : th)
        x = thread(count10000);
    for (thread &x : th)
        x.join();
    cout << n << endl;
    return 0;
}

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 // #include <mutex> //这个例子不需要mutex了
 6 #include <atomic>
 7 using namespace std;
 8 atomic_int n = 0;
 9 void count10000() {
10     for (int i = 1; i <= 10000; i++) {
11         n++;
12     }
13 }
14 int main() {
15     thread th[100];
16     for (thread &x : th)
17         x = thread(count10000);
18     for (thread &x : th)
19         x.join();
20     cout << n << endl;
21     return 0;
22 }

 

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 #include <future>
 6 using namespace std;
 7 int main() {
 8     async(launch::async, [](const char *message){
 9         cout << message << flush;
10     }, "Hello, ");
11     cout << "World!" << endl;
12     return 0;
13 }

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 // #include <thread> // 这里我们用async创建线程
 5 #include <future> // std::async std::future
 6 using namespace std;
 7 
 8 template<class ... Args> decltype(auto) sum(Args&&... args) {
 9     // C++17折叠表达式
10     // "0 +"避免空参数包错误
11     return (0 + ... + args);
12 }
13 
14 int main() {
15     // 注:这里不能只写函数名sum,必须带模板参数
16     future<int> val = async(launch::async, sum<int, int, int>, 1, 10, 100);
17     // future::get() 阻塞等待线程结束并获得返回值
18     cout << val.get() << endl;
19     return 0;
20 }

例八:void特化std::future
 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <future>
 5 using namespace std;
 6 void count_big_number() {
 7     // C++14标准中,可以在数字中间加上单
 8     // 引号 ' 来分隔数字,使其可读性更强
 9     for (int i = 0; i <= 10'0000'0000; i++);
10 }
11 int main() {
12     future<void> fut = async(launch::async, count_big_number);
13     cout << "Please wait" << flush;
14     // 每次等待1秒
15     while (fut.wait_for(chrono::seconds(1)) != future_status::ready)
16         cout << '.' << flush;
17     cout << endl << "Finished!" << endl;
18     return 0;
19 }

// Compiler: MSVC 19.29.30038.1
// C++ Standard: C++17
#include <iostream>
using namespace std;
constexpr long double PI = 3.14159265358979323846264338327950288419716939937510582097494459230781640628;
// 给定圆的半径r,求圆的直径、周长及面积
void get_circle_info(double r, double &d, double &c, double &s) {
    d = r * 2;
    c = PI * d;
    s = PI * r * r;
}
int main() {
    double r;
    cin >> r;
    double d, c, s;
    get_circle_info(r, d, c, s);
    cout << d << ' ' << c << ' ' <<  s << endl;
    return 0;
}

例十一:std::promise的使用

以例七中的代码为基础加以修改:

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 #include <future> // std::promise std::future
 6 using namespace std;
 7 
 8 template<class ... Args> decltype(auto) sum(Args&&... args) {
 9     return (0 + ... + args);
10 }
11 
12 template<class ... Args> void sum_thread(promise<long long> &val, Args&&... args) {
13     val.set_value(sum(args...));
14 }
15 
16 int main() {
17     promise<long long> sum_value;
18     thread get_sum(sum_thread<int, int, int>, ref(sum_value), 1, 10, 100);
19     cout << sum_value.get_future().get() << endl;
20     get_sum.join(); // 感谢评论区 未来想做游戏 的提醒
21     return 0;
22 }

 

 1 #include <iostream>
 2 #include <thread>
 3 #include <atomic>
 4 using namespace std;
 5 atomic_bool ready = 0;
 6 // uintmax_t ==> unsigned long long
 7 void sleep(uintmax_t ms) {
 8     this_thread::sleep_for(chrono::milliseconds(ms));
 9 }
10 void count() {
11     while (!ready) this_thread::yield();
12     for (int i = 0; i <= 20'0000'0000; i++);
13     cout << "Thread " << this_thread::get_id() << " finished!" << endl;
14     return;
15 }
16 int main() {
17     thread th[10];
18     for (int i = 0; i < 10; i++)
19         th[i] = thread(::count);
20     sleep(5000);
21     ready = true;
22     cout << "Start!" << endl;
23     for (int i = 0; i < 10; i++)
24         th[i].join();
25     return 0;
26 }

 转自:https://blog.csdn.net/sjc_0910/article/details/118861539

posted @ 2023-11-24 16:49  量子与太极  阅读(224)  评论(0编辑  收藏  举报