首页天道酬勤C++并发编程总结

C++并发编程总结

admin 03-18 14:25 97次浏览

文章目录

1.第二章小结

1.第二章小结

登录后复制 

#include <iostream>

#include <thread> //①

#include <vector>

#include <algorithm>

void hello() // ②

{

    std::cout << "Hello Concurrent World\n";

}


class background_task

{

public:

    void do_something() const {}

    void do_something_else() const {}

    void operator()() const

    {

        do_something();

        do_something_else();

    }

};


struct func

{

    int &i;

    func(int &i_) : i(i_) {}

    void operator()()

    {

        for (unsigned j = 0; j < 1000000; ++j)

        {

            std::cout << j; // 1. 潜在访问隐患:悬空引用

            std::cout.flush();

        }

    }

};

void oops()

{

    int some_local_state = 0;

    func my_func(some_local_state);

    std::thread my_thread(my_func);

    my_thread.detach(); // 2. 不等待线程结束

} // 3. 新线程可能还在运行


// 解决线程生命周期的方法1

// void f()

// {

//     int some_local_state = 0;

//     func my_func(some_local_state);

//     std::thread t(my_func);

//     try

//     {

//         do_something_in_current_thread();

//     }

//     catch (...)

//     {

//         // 在异常处理过程中调用join(),从而避免生命周期的问题

//         t.join(); // 1

//         throw;

//     }

//     t.join(); // 2

// }


// 解决线程生命周期的方法2,使用RAII等待线程完成

// class thread_guard

// {

//     std::thread &t;


// public:

//     explicit thread_guard(std::thread &t_) : t(t_)

//     {

//     }

//     ~thread_guard()

//     {

//         if (t.joinable()) // 1

//         {

//             t.join(); // 2

//         }

//     }

//     thread_guard(thread_guard const &) = delete; // 3

//     thread_guard &operator=(thread_guard const &) = delete;

// };

// struct func; // 定义在清单2.1中

// void f()

// {

//     int some_local_state = 0;

//     func my_func(some_local_state);

//     std::thread t(my_func);

//     thread_guard g(t);

// 即使do_something_in_current_thread抛出一个异常,这个销毁依旧会发生

//     do_something_in_current_thread();

// } // 4


// std::thread和std::bind中若函数对象的参数带引用,需要注意的问题

using widget_data = std::int16_t;

using widget_id = std::int16_t;

void update_data_for_widget(widget_id w, widget_data &data) // 1

{

    data = 10;

}

void oops_again(widget_id w)

{

    widget_data data = 0;

    // std::thread t(update_data_for_widget, w, data); // error:C++:std::thread arguments must be invocable after conversion to rvalues

    // 这是因为thread本身的构造函数的参数:Args&&... __args造成的,

    //虽然转发类型能提供引用,但是thread构造函数这里使用了std::decay,去掉了引用属性,所以需要自己增加引用属性,所以需要添加std::ref

    std::thread t(update_data_for_widget, w, std::ref(data)); // 2,ok

    t.join();

}


// std::thread支持移动,但不可拷贝

void test()

{

    void some_function();

    void some_other_function();

    std::thread t1(some_function);         // 1

    std::thread t2 = std::move(t1);        // 2

    t1 = std::thread(some_other_function); // 3,为什么不显式调用std::move()转移所有权呢?因为,所有者是一个临时对象——移动操作将会隐式的调用。

    std::thread t3;                        // 4

    t3 = std::move(t2);                    // 5

    t1 = std::move(t3);                    // 6 赋值操作将使程序崩溃,不能通过赋一个新值给std::thread对象的方式来”丢弃”一个线程

}


//  函数返回std::thread对象

std::thread f()

{

    void some_function();

    return std::thread(some_function);

}

std::thread g()

{

    void some_other_function(int);

    std::thread t(some_other_function, 42);

    return t;

}


// std::thread实例可作为参数进行传递

void f(std::thread t);

void g2()

{

    void some_function();

    f(std::thread(some_function));

    std::thread t(some_function);

    f(std::move(t));

}

// scoped_thread的用法

class scoped_thread

{

    std::thread t;


public:

    explicit scoped_thread(std::thread t_) : // 1

                                             t(std::move(t_))

    {

        if (!t.joinable()) // 2

            throw std::logic_error("No thread");

    }

    ~scoped_thread()

    {

        t.join(); // 3

    }

    scoped_thread(scoped_thread const &) = delete;

    scoped_thread &operator=(scoped_thread const &) = delete;

};

struct func; // 定义在清单2.1中

void f3()

{

    int some_local_state;

    scoped_thread t(std::thread(func(some_local_state))); // 4

    do_something_in_current_thread();

} // 5


// 量产线程,等待它们结束

void do_work(unsigned id);

void f2()

{

    std::vector<std::thread> threads;

    for (unsigned i = 0; i < 20; ++i)

    {

        threads.push_back(std::thread(do_work, i)); // 产生线程

    }

    std::for_each(threads.begin(), threads.end(),

                  std::mem_fn(&std::thread::join)); // 对每个线程调用join()

}


// std::thread::id实例常用作检测线程是否需要进行一些操作

/*

主线程可能要做一些与其他线程不同的工作。这种情况下,启动其他线程前,它

可以将自己的线程ID通过std::this_thread::get_id()得到,并进行存储。就是算法核心部分(所有线程都一样的),每个线程都要检查一下,其拥有的线程ID是否与初始线程的ID相同。

*/

std::thread::id master_thread;

void some_core_part_of_algorithm()

{

    if (std::this_thread::get_id() == master_thread)

    {

        do_master_thread_work();

    }

    do_common_work();

}


int main()

{

    // 传递了一个临时变量

    //  std::thread t(background_task()); // error,C++编译器会将其解析为函数声明,而不是类型对象的定义。

    // std::thread t((background_task())); // ok

    std::thread t{background_task()}; // ok


    // t.join(); // ④

    // oops();


    oops_again(1);

}


【小程序】实时截屏上传到服务器 C++模板(第二版)笔记之第十章:模板基本术语