美文网首页程序员
C++ 并发编程学习(三)

C++ 并发编程学习(三)

作者: rmrfany | 来源:发表于2018-12-21 11:39 被阅读6次

    向线程函数传递参数

    一. 传参const char*

    void f(int i, std::string const& s);
    std::thread t(f, 3, "hello");
    

      函数f需要一个 std::string 对象作为第二个参数,但这里使用的是字符串的字面值,也就是 char const * 类型。之后,在线程的上下文中完成字面值向 std::string 对象的转化。

    二. 传参指向动态变量的指针

    void f(int i,std::string const& s);
    void not_oops(int some_param)
    {
        char buffer[1024];
        sprintf(buffer,"%i",some_param);
        std::thread t(f,3,std::string(buffer)); // 使用std::string,避免悬垂指针
        t.detach();
    }
    

      buffer是一个指针变量,指向本地变量,然后本地变量通过buffer传递到新线程中。并且,函数有很有可能会在字面值转化成 std::string 对象之前崩溃(oops),从而导致一些未定义的行为。并且想要依赖隐式转换将字面值转换为函数期待的 std::string 对象,但因 std::thread 的构造函数会复制提供的变量,就只复制了没有转换成期望类型的字符串字面值。解决方案就是在传递到 std::thread 构造函数之前就将字面值转化为std::string 对象。

    三.传参期望传递一个引用

    void update_data_for_widget(widget_id w,widget_data& data); // 1
    void oops_again(widget_id w){
        widget_data data;
        std::thread t(update_data_for_widget,w,data); // 2
        display_status();
        t.join();
        process_widget_data(data); // 3
    }
    

      虽然update_data_for_widget的第二个参数期待传入一个引用,但是 std::thread 的构造函数并不知晓;构造函数无视函数期待的参数类型,并盲目的拷贝已提供的变量。当线程调用update_data_for_widget函数时,传递给函数的参数是data变量内部拷贝的引用,而非数据本身的引用。因此,当线程结束时,内部拷贝数据将会在数据更新阶段被销毁,且process_widget_data将会接收到没有修改的data变量。可以使用 std::ref 将参数转换成引用的形式,从而可将线程的调用改为以下形式:

    std::thread t(update_data_for_widget,w,std::ref(data)
    

      在这之后,update_data_for_widget就会接收到一个data变量的引用,而非一个data变量拷贝的引用。

    四. std::move 的用法

    void process_big_object(std::unique_ptr<big_object>);
    std::unique_ptr<big_object> p(new big_object);
    p->prepare_data(42);
    std::thread t(process_big_object,std::move(p));
    

      在 std::thread 的构造函数中指定 std::move(p) ,big_object对象的所有权就被首先转移到新创建线程的的内部存储中,之后传递给process_big_object函数。标准线程库中和 std::unique_ptr 在所属权上有相似语义类型的类有好几种, std::thread 为其中之一。虽然, std::thread 实例不像 std::unique_ptr 那样能占有一个动态对象的所有权,但是它能占有其他资源:每个实例都负责管理一个执行线程。执行线程的所有权可以在多个 std::thread 实例中互相转移,这是依赖于 std::thread 实例的可移动且不可复制性。不可复制保性证了在同一时间点,一个 std::thread 实例只能关联一个执行线程;可移动性使得程序员可以自己决定,哪个实例拥有实际执行线程的所有权。

    相关文章

      网友评论

        本文标题:C++ 并发编程学习(三)

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