Windows 多线程编程入门(2)

简单总结下C++自带的 std::thread
优点:
1. 简单,易用
2. 跨平台,pthread只能用在POSIX系统上(其他系统有其独立的thread实现)
3. 提供了更多高级功能,比如future
4. 更加C++(跟匿名函数,std::bind,RAII等C++特性更好的集成

缺点:
1. 没有RWlock。有一个类似的shared_mutex,不过它属于C++14,你的编译器很有可能不支持。
2. 操作线程和Mutex等的API较少。毕竟为了跨平台,只能选取各原生实现的子集。如果你需要设置某些属性,需要通过API调用返回原生平台上的对应对象,再对返回的对象进行操作。

joinable函数
检查线程是否可被 join。检查当前的线程对象是否表示了一个活动的执行线程,由默认构造函数创建的线程是不能被 join 的。另外,如果某个线程 已经执行完任务,但是没有被 join 的话,该线程依然会被认为是一个活动的执行线程,因此也是可以被 join 的。

t.joinable();

native_handle函数
由于 std::thread 的实现和操作系统相关,因此该函数返回与 std::thread 具体实现相关的线程句柄,例如在符合 Posix 标准的平台下(如 Unix/Linux)是 Pthread 库

yield函数
当前线程放弃执行,操作系统调度另一线程继续执行。

std::this_thread::yield();

hardware_concurrency 函数
此函数为静态函数,用于检测硬件并发特性,返回当前平台的线程实现所支持的线程并发数目,但返回值仅仅只作为系统提示(hint)。

条件变量
作为线程同步的重要方法,std::thread,也支持了condition_variable:当某些条件不满足时,停止执行直到该条件被满足。

在经典的生产者消费者模式下,生产者和消费者就是通过condition variable来实现同步的。当有限的生产力无法满足日益增长的消费需求时,消费者进程就会去睡一觉,直到它想要的东西生产出来才醒来

condition_variable需要和 unique_lock搭配使用。在一个线程调用wait之前,它必须持有unique_lock锁。当wait被调用时,该锁会被释放,线程会陷入沉睡,等待着王子生产者发过来的唤醒信号。当生产者调用同一个condition_variable的 notify_all方法时,所有沉睡在该变量前的消费者会被唤醒,并尝试重新获取之前释放的unique_lock,继续执行下去。(注意这里发生了锁争用,只有一个消费者能够获得锁,其他消费者得等待该消费者释放锁)。如果只想叫醒一个线程,可以用notify_one

wait可以接受两个参数。此时第二个参数用于判断当前是否要沉睡

[]{ return msgQueue.size() > 0;});

while (msgQueue.size() <= 0) {
    condvar.wait()
}

这里把沉睡的线程比作睡美人,万一王子变成了青蛙,来不及唤醒她,那睡美人不就得睡到天荒地老海枯石烂?

扫描二维码关注公众号,回复: 1513556 查看本文章

为了解决这个问题,通过wait_until和wait_for,你可以设定线程的等待时间。设置notify_all_at_thread_exit也许能帮得上忙。

atomic
它提供了一组轻量级的、作用在单个变量上的原子操作。atomic位于头文件atomic。内容不会被线程的切换所打断。

/*time:20180605
  author:MISAYAONE
  */
#include<iostream>
#include<thread>
#include<Windows.h>
#include<mutex>
#include<condition_variable>
#include<queue>
using namespace std;

mutex mu_msg;
condition_variable cv_msg;
//消费者,生产者模式的简单实现(利用条件变量和互斥锁)
queue<int> msg_queue;
void producer(int start, int end)
{
    for (int i=start;i<end;i++)
    {
        mu_msg.lock();
        msg_queue.push(i);
        mu_msg.unlock();
    }
    cout << "msg produced" << endl;
    if (msg_queue.size() > 20)
    {
        cv_msg.notify_all();//沉睡在该变量上的所有线程都将被唤醒,并尝试获取互斥锁(只有一个消费者可获得互斥锁)
    }
}

void consumer(int demand)
{
    while (true)
    {
        unique_lock<std::mutex> ulock(mu_msg);
        cv_msg.wait(ulock,[] {return msg_queue.size() > 0;});//尝试获取互斥锁,否则等待
        printf("Consume msg %d\n", msg_queue.front());
        msg_queue.pop();
        --demand;
        if (!demand)
        {
            break;
        }
    }
}

mutex mu;//互斥锁对象

int num = 100;
void thread_func1()
{
    for (int i=0;i<10;i++)
    {
        cout <<"thread 1's "<< i << endl;
        Sleep(100);
    }

    while (num>0)//这里不能用while,好无知....
    {
        mu.lock();//互斥锁加锁
        cout << "1还在执行" << num << endl;
        num--;
        mu.unlock();//互斥锁解锁
        if (num < 50)
        {
            //当前线程就不再执行
            this_thread::yield();
            break;
        }
    }




}

void thread_func2(int n)
{
    for (int i = 0; i<n; i++)
    {
        cout <<"thread 2's "<< i << endl;
        Sleep(200);
    }
    while (num>0)
    {
        mu.lock();
        cout <<"2还在执行"<< num << endl;
        num--;
        mu.unlock();
    }

}

class A
{
public :
        void thread_func3()
        {
            for (int i = 0; i<10; i++)
            {
                cout << "class A thread 3's " << i << endl;
                Sleep(200);
            }
        }

};

class thread_guard
{
    thread &t;
public:
    explicit thread_guard(thread& _t):t(_t){}
    ~thread_guard()
    {
        if (t.joinable())
        {
            t.join();
        }
    }
    //拷贝赋值默认去除
    thread_guard(const thread_guard&) = delete;
    thread_guard& operator=(const thread_guard&) = delete;
};

int main()
{
    A a;
    thread task00();//默认构造函数

    thread task01(thread_func1);//正常构造函数
    thread_guard g(task01);//出现异常后,函数退出,g局部对象对销毁,此时g调用析构函数,会自动执行task01的join函数,从而能够保证join一定会被调用
    thread task02(thread_func2,10);//带args的线程构造函数
    //thread task_i(move(task02));//转移线程所有权,此时再利用task02调用join和detach会报错
    thread task03(&A::thread_func3,a);//传入类的成员函数作为线程构造函数的参数

    if (task01.joinable())//此处不可以使用task00线程来判断
    {
        cout << "task01 is joinable" << endl;
    }


    //join函数顺序执行线程
    task01.join();
    task02.join();
    //task_i.join();
    //task03.join();

    //不影响当前代码的执行,几个线程后台自行执行,不阻塞主线程
    //task01.detach();
    //task02.detach();
    //task_i.detach();
    task03.detach();

    //lambda匿名函数
    for (int j=0;j<20;j++)
    {
        thread t([j]() {cout << j << endl; });
        t.detach();
    }

    for (int i = 0; i<10; i++)
    {
        cout << "main thread's " << i << endl;
        Sleep(200);
    }

    cout << "task01.get_id() = " << task01.get_id() << endl;//获取线程ID

    unsigned int core_num = std::thread::hardware_concurrency();
    cout << "CPU 核数" << core_num << endl;

    thread mutiple00(producer, 10, 20);
    thread mutiple01(producer, 20, 30);
    thread mutiple02(producer, 30, 40);
    thread mutiple03(consumer, 5);
    thread mutiple04(consumer, 8);

    mutiple00.join();
    mutiple01.join();
    mutiple02.join();
    mutiple03.join();
    mutiple04.join();


    cin.get();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/misayaaaaa/article/details/80596717
今日推荐