zoukankan      html  css  js  c++  java
  • C++ 并行编程《一》

    1.最简单的C++多线程程序

    #include <iostream>
    #include <thread>
    
    void do_something()
    {
        std::cout << "func do_something..." << std::endl;
    }
    
    int main(int argc, char *argv[])
    {
    
        std::thread my_thread(do_something);
        std::cout << "main thread" << std::endl;
        my_thread.join();
        return 0;
    }

    2.在C++标准中,std::thread可以和任何可调用(callable)类型一同工作,所以,我们可以给std::thread构造函数传递一个带有函数调用操作符的类实例,代替直接传入的函数。

    #include <iostream>
    #include <thread>
    
    void do_something()
    {
        std::cout << "func do_something" << std::endl;
    }
    
    class background_task
    {
    public:
        void operator()() const
        {
            do_something();
        }
    };
    
    int main(int argc, char *argv[])
    {
        background_task bt;
        std::thread my_thread(bt);      /* 传入一个类实例 */
        std::cout << "main thread" << std::endl;
        my_thread.join();
    
        return 0;
    }

    3.等待线程结束,C++有两种线程结束的方法(join、detach)。对于detach()方法来讲,即使线程实例被主线程销毁,线程依旧可以后台执行,直到自行结束。

    而对于join()方法,主线程会等待子线程的执行,并获得子线程的返回值。问题是,我们在什么地方等待子线程结束,如果发生异常,怎样保证子线程依旧能够正确结束。一种方法如下:

    #include <iostream>
    #include <thread>
    
    void do_something()
    {
        std::cout << "func do_something..." << std::endl;
    }
    
    class background_task
    {
    public:
        void operator()()
        {
            do_something();
        }
        background_task(int val)
        {
            std::cout << "background_task constructor init" << std::endl;
        }
    };
    
    int main(int argc, char *argv[])
    {
        int init_val = 0;
        background_task bt(init_val);
    
        std::thread my_thread(bt);
    
        try
        {
            std::cout<<"err occured here"<<std::endl; /* 错误发生位置 */
        }
        catch (...)
        {
            my_thread.join();                         /* 为了保证线程在异常情况下也能正常结束 */
            throw;
        }
        my_thread.join();                             /* 计划结束位置 */
        return 0;
    }

    4.使用try/catch方式结束进程,不仅使代码阅读性降低,而且容易将作用域搞乱,因此需要一种更高明的方法。这样做的方法之一是使用资源获取即初始化(RALL)惯用语法。

    如下:

    #include <iostream>
    #include <thread>
    
    class thread_guard
    {
        std::thread &t;           /* 定义一个别名,将传入的线程复制给它 */
    
    public:
        explicit thread_guard(std::thread &t_) : t(t_) {}
        ~thread_guard()
        { /* 将进程结束操作和类资源释放绑定 ,只要类被释放,线程就会结束 */
            if (t.joinable())
            {
                t.join();
            }
        }
        thread_guard(thread_guard const &) = delete;
        thread_guard &operator=(thread_guard const &) = delete;
    };
    
    void do_something()
    {
        std::cout << "func do_something" << std::endl;
    }
    
    struct func
    {
        int &i;
        func(int &i_) : i(i_) {}
        void operator()()
        {
            do_something();
        }
    };
    
    /* 一个简单明了的,能够保证在异常情况下也能正常结束线程的方法 */
    int main(int argc, char *argv[])
    {
        int init_val = 0;
        func my_func(init_val);
        std::thread my_thread(my_func);
        thread_guard g(my_thread);
        return 0;                          /* 主线程结束后,会销毁局部变量, 在g被销毁时,会等待子线程结束 */
    }
  • 相关阅读:
    利用python爬虫关键词批量下载高清大图
    多源最短路径算法—Floyd算法
    Dijkstra算法详细(单源最短路径算法)
    写博客没高质量配图?python爬虫教你绕过限制一键搜索下载图虫创意图片!
    并查集(不相交集合)详解与java实现
    AVL树(二叉平衡树)详解与实现
    二叉树——前序遍历、中序遍历、后序遍历、层序遍历详解(递归非递归)
    CSS基础总结
    HTML基础总结
    JavaSE 软件工程师 认证考试试卷3
  • 原文地址:https://www.cnblogs.com/PPWEI/p/11422424.html
Copyright © 2011-2022 走看看