美文网首页
C++11 线程管理

C++11 线程管理

作者: 疯狂小王子 | 来源:发表于2017-07-29 22:29 被阅读0次
    1 线程启动
    2 参数传递
      2.1 参数传递
      2.2 引用传参
    3 线程所有权管理
    4 线程标志
    

    1 线程启动

    std::thread构造函数接受可调用对象启动线程,如下所示:

    #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();
    }
    

    假设文件名为thread.cpp, 则编译命令为:
    g++ -std=c++11 -lpthread thread.cpp -o test_thread
    执行./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 参数传递

    2.1 基本范例

    下面例子是一个向线程传递参数的示例

    #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();
    }
    

    这个程序存在一个隐患, 由于主进程detach了,所以buffer在转成std::string之前有可能因为主进程退出而销毁,正确的方式是在主进程中就把buffer转成std::string, 如下

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

    2.2 引用传参

    C++11 支持使用std::ref向线程按照引用方式传递参数, 如下范例:

    #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;
    }
    

    程序输出结果为:

    i=1
    s=update value
    

    3 线程所有权管理

    std::thread都是可移动,但不可拷贝, 如下面示例:

    #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
    

    对于需要join的线程,为了确保join一定会被调用,可以创建下面的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中,批量创建线程并且等待它们结束,示例如下:

    #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 线程标志

    线程标识类型是std::thread::id,可以通过两种方式进行检索。第一种,可以通过调用std::thread对象的成员函数get_id()来直接获取。如果std::thread对象没有与任何执行线程相关联,get_id()将返回std::thread::type默认构造值,这个值表示“没有线程”。第二种,当前线程中调用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
    

    相关文章

      网友评论

          本文标题:C++11 线程管理

          本文链接:https://www.haomeiwen.com/subject/fotvhxtx.html