C++ 并发编程之std::thread的基本用法

C++ 并发编程之std::thread的基本用法

一.基本用法

#include<iostream>
#include<thread>

using namespace std;
void show(const char str[], const int id)
//  void show(const char *str, const int id)
{
    cout << "线程 " << id + 1 << " :" << str << endl;
}
int main()
{
    thread t1(show, "hello cplusplus!", 0);
    t1.join();
    thread t2(show, "你好,C++!", 1);
    t2.join();
    thread t3(show, "hello!", 2);
    t3.join();
    return 0;
}
#include <iostream>
#include <thread>
using namespace std;
void sayHello();
void show();
void method(int &a)//ref
{
    a += 5;
    cout <<a<<endl;
}
int main(int argc, char const *argv[]) {

    int a = 0;
    thread th1(&method,ref(a));//ref !!
    thread th1_move = thread(move(th1));//move constructor,th1被转移到th1_move后th1被销毁,类似于剪切
    th1_move.join();
    thread t11 (&sayHello);
    t11.join();
    cout <<"world"<<endl;
    cout<<"------------"<<endl;
     //栈上 
    thread t1(show);   //根据函数初始化执行
    thread t2(show);
    thread t3(show);
    //线程数组
    thread th[3]{thread(show), thread(show), thread(show)};
    //堆上
    thread *pt1(new thread(show));
    thread *pt2(new thread(show));
    thread *pt3(new thread(show));
    //线程指针数组
    thread *pth(new thread[3]{thread(show), thread(show), thread(show)});
    return 0;
}
void sayHello()
{
    cout<<"hello"<<endl;
}

void show()
{
    cout << "hello cplusplus!" << endl;
}

在传递参数时候需要注意,thread使用的是参数的拷贝,因此要求可调度物和参数类型都支持拷贝构造。如果希望传递给线程引用值就需要使用ref库进行包装,同时保证被引用对象在线程执行期间一直存在,否则会引发未定义行为。
二.多线程传递参数



    #include<iostream>
    #include<thread>

    using namespace std;
    void show(const char str[], const int id)
    {
        cout << "线程 " << id + 1 << " :" << str << endl;
    }
    int main()
    {
        thread t1(show, "hello cplusplus!", 0);
        t1.join();
        thread t2(show, "你好,C++!", 1);
        t2.join();
        thread t3(show, "hello!", 2);
        t3.join();
        return 0;
    }

三.线程的join和detach

#include<iostream>
#include<thread>
#include<array>
using namespace std;
void show()
{
    cout << "hello cplusplus!" << endl;
}
int main()
{
    thread th = thread(show);
    th.detach();//脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。
    //detach以后,子线程会成为孤儿线程,线程之间将无法通信。
    cout << th.joinable() << endl;
    //th.join(); //error
    array<thread, 3>  threads = { thread(show), thread(show), thread(show) };
    for (int i = 0; i < 3; i++)
    {
        cout << threads[i].joinable() << endl;//判断线程是否可以join
        threads[i].join();//主线程等待当前线程执行完成再退出
    }
    return 0;
}

注意:

无论在windows中还是Posix中,主线程和子线程的默认关系是:无论子线程执行完毕与否,一旦主线程执行完毕退出,所有子线程执行都会终止。这时整个进程结束或僵死,部分线程保持一种终止执行但还未销毁的状态,而进程必须在其所有线程销毁后销毁,这时进程处于僵死状态。线程函数执行完毕退出,或以其他非常方式终止,线程进入终止态,但是为线程分配的系统资源不一定释放,可能在系统重启之前,一直都不能释放,终止态的线程,仍旧作为一个线程实体存在于操作系统中,什么时候销毁,取决于线程属性。在这种情况下,主线程和子线程通常定义以下两种关系:

1、可会合(joinable):这种关系下,主线程需要明确执行等待操作,在子线程结束后,主线程的等待操作执行完毕,子线程和主线程会合,这时主线程继续执行等待操作之后的下一步操作。主线程必须会合可会合的子线程。在主线程的线程函数内部调用子线程对象的wait函数实现,即使子线程能够在主线程之前执行完毕,进入终止态,也必须执行会合操作,否则,系统永远不会主动销毁线程,分配给该线程的系统资源也永远不会释放。

2、相分离(detached):表示子线程无需和主线程会合,也就是相分离的,这种情况下,子线程一旦进入终止状态,这种方式常用在线程数较多的情况下,有时让主线程逐个等待子线程结束,或者让主线程安排每个子线程结束的等待顺序,是很困难或不可能的,所以在并发子线程较多的情况下,这种方式也会经常使用。

在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。
join()是个简单暴力的方法:新线程调用join()之后,主线程会一直等待新进程,直到新线程执行完毕(Waits for this thread to die)。
而detach()将本线程从调用线程中分离出来,允许本线程独立执行。分离线程没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。但是当主进程结束的时候,即便是detach出去的子线程不管有没有完成都会被强制杀死。
简言之,main()函数结束了线程对象就析构了,如果线程没执行完那就爆炸了。
所以调用join阻塞,等待线程执行完毕。
或者用detach放到后台,不过放到后台你就没法控制它了,这个时候该thread对象不代表任何线程体,joinable()=false。

四.lambda表达式和thread结合

#include<iostream>
#include<thread>
using namespace std;
int main()
{
    auto fun = [](const char *str) {cout << str << endl; };
    thread t1(fun, "hello world!");
    t1.join();

    thread t2(fun, "hello beijing!");
    t2.join();
    return 0;
}

五.线程交换

#include <iostream>
#include <thread>

using namespace std;

int main()
{
    thread t1([]()
    {
        cout << "thread1" << endl;
    });
    thread t2([]()
    {
        cout << "thread2" << endl;
    });
    cout << "thread1' id is " << t1.get_id() << endl;
    cout << "thread2' id is " << t2.get_id() << endl;

    cout << "swap after:" << endl;
    swap(t1, t2);//线程交换
    cout << "thread1' id is " << t1.get_id() << endl;
    cout << "thread2' id is " << t2.get_id() << endl;
    t1.join();
    t2.join();

    return 0;
}

六.线程移动

#include <iostream>
#include <thread>

using namespace std;
int main()
{
    thread t1([]()
    {
        cout << "thread1" << endl;
    });
    cout << "thread1' id is " << t1.get_id() << endl;
    thread t2 = move(t1);

    cout << "thread2' id is " << t2.get_id() << endl;
    t2.join();
    return 0;
}

出处:C++11并发之std::thread: http://blog.csdn.net/liuker888/article/details/46848905

发布了78 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43778179/article/details/105071155