第四章(同步并发操作)

1、条件变量

线程1完成后,通知其它线程它执行完成了。通过条件变量实现

void CTestThreadCondition::Preparation_Thread()
{
    while (true)
    {
        long ldata = clock();
        std::lock_guard<std::mutex> guard(dataMutex_);
        if (ldata >= lEndMark - 5000)
        {
            vsData_.push(ldata);
            data_cond_.notify_one();
            break;
        }
        std::this_thread::sleep_for(chrono::milliseconds(1000));
    }
}


void CTestThreadCondition::TestCondition()
{
    lEndMark = clock() + 15000;
    thread thread2(&CTestThreadCondition::Preparation_Thread, this);
    thread2.detach();

    while (true)
    {
        std::unique_lock<std::mutex> lk(dataMutex_);
        data_cond_.wait(lk, [this]{return !vsData_.empty(); }); // 匿名函数,等待vsData值是否不为空了

        long lPop = vsData_.front();
        vsData_.pop();
        lk.unlock();

        cout << lPop<<endl;

        if (lPop >= lEndMark)
        {
            break;
        }
    }
}


此处需要使用unique_lock,因为它里面支持unlock,lock接口,而条件变量正是利用这两个接口来实现通知等待的

wait接口需要传入函数指针,用来判断接受到信号后事继续wait还是往下执行,部分wait源码。收到notify_one后,wait(_Lck)就会往下执行

然后判断!_Pred(),如果此时该函数还是返回false,那就需要等待下一次的notify_one了。

template<class _Predicate>
  void wait(unique_lock<mutex>& _Lck, _Predicate _Pred)
  { // wait for signal and test predicate
  while (!_Pred())
   wait(_Lck);
  }

wait(_Lck)中会先将lk执行unlock。wait成功接受会,再将其lock。此时如果有其它线程(比如notify_one后它的lk未执行unlock)占用这把锁,也是无法继续往下执行的

条件变量时和信号量一起使用的,需要注意它对信号量的一些操作和改变,它依赖于信号量

notify_all是通知所有等待该信号的wait方法,notify_one是通知某一个,尽量一个信号一个等待。notify_all后信号量还是只能一个锁定


2、future

接受到线程的返回值

int Accumute(int i)
{
    Sleep(3000);
    return i;
}

void CTestThreadCondition::TestFutureGet()
{
    // async的构造函数接受的是一个右值引用&&
    // 第一个参数可以不传,不传与传入async目前看来是一样的,都表示在一个新的线程中立刻运行Accumute
    std::future<int> the_answer1 = std::async(std::launch::async, Accumute, 10);
    the_answer1.wait();  // wait会堵塞,直到the_answer1的线程执行返回结果
    int iRet1 = the_answer1.get(); // wait堵塞完后,get中存储的该值。如果不适用wait直接用get也是一样的会堵塞直到返回值

    std::future<int> the_answer2 = std::async(Accumute, 20); // 与上面一样
    Sleep(4000);
    the_answer2.wait();
    int iRet2 = the_answer2.get();

    // 传入deferred,表示不立刻运行,等到future调用wait或则get时才开始运行
    // wait表示等待线程运行完成,get是获取结果,也可以不调用wait,直接调用get也会进行等待线程执行完成的
    std::future<int> the_answer3 = std::async(std::launch::deferred, Accumute, 30);
    Sleep(4000);
    the_answer3.wait();
    int iRet3 = the_answer3.get();
}


3、packaged_task

将任务打包


void CTestThreadCondition::gui_thread()
{
    while (true)
    {
        packaged_task<int(int)> task; // 当前待处理的任务
        {
            lock_guard<mutex> lock(taskMutex_);
            if (Tasks_.empty())
            {
                Sleep(10);
                continue;
            }
            task = std::move(Tasks_.front());
            Tasks_.pop_front();
        }
        task(10); // 参数如何传递???
    }
}


void CTestThreadCondition::TestFuturePackaged()
{
    thread thread1(&CTestThreadCondition::gui_thread, this);
    // 将任务放到一个队列中,然后线程不断从队列中取值进行执行
    packaged_task<int(int)> task(Accumute); // 将函数指针放到一个packaged_task中,支持通过task转换成future,也可以直接执行task
    future<int> res = task.get_future();

    // task(1); // 也可以直接调用,然后res去get,此时会堵塞。task就是直接调用函数了
    {
        lock_guard<mutex> lock(taskMutex_);
        Tasks_.push_back(std::move(task)); // 放到队列中,在其它线程取值
    }

    int iRet = res.get();
   
    thread1.join();
}


4、Promise

void CTestThreadCondition::TestFuturePromise()
{
    std::promise<int> PromiseTask;

    PromiseTask.set_value(Accumute(10)); // setvalue就开始执行Accumute了?

    future<int> futureTask = PromiseTask.get_future();

    int aa = futureTask.get();

    // 多次get会崩溃
    //int aa2 = futureTask.get();
}


5、shared_future

多个线程等待future的值

void CTestThreadCondition::TestSharedFuture()
{
    // future只能等待一个future。如果多个线程都想要得到future的值,多次get会崩溃。这是故意这样设计的。为了统一异步结果的所有权
    // 此时需要使用shared_future
    promise<int> p1;
    future<int> f(p1.get_future());
    assert(f.valid());

    shared_future<int> sf(std::move(f));
    // 也可以直接通过future的shared接口直接转移所有权
    //shared_future<int> sf = f.share();

    assert(!f.valid());
    assert(sf.valid());
}


6、时钟

chrono标准库中部分接口,代替windows中sleep接口的方法:this_thread::sleep_for

sleep_for表示等待多少时间,sleep_unit表示等待到某个时间点。其它接口_for,_unit也是一样的。

void CTestThreadCondition::TestTime()
{
    chrono::system_clock::time_point tmNow = chrono::system_clock::now();

    future<int> f = async(Accumute, 10);
    if (f.wait_for(std::chrono::microseconds(4*1000*1000)) == future_status::ready) // microseconds是微秒
    {
        cout<< "f.get()"<<f.get()<<endl;
    }

    future<int> f2 = async(Accumute, 10);
    if (f2.wait_until(chrono::steady_clock::now() + chrono::milliseconds(4000)) == future_status::ready) // milliseconds是毫秒
    {
        cout << "f2.get()" << f2.get() << endl;
    }
}


this_thread::sleep_for/sleep_until

conditon_variable::wait_for/wait_until

conditon_variable_any::wait_for/wait_until

time_mutex::try_lock_for/try_lock_until

recursive_time_mutex::try_lock_for/try_lock_unitl

unique_lock<timeLockable>::unique_lock/unique_lock(lockable,time_point/duration)

future<valuetype>::wait_for/wait_until

shared_future<valuetype>::wait_for/wait_until





你可能感兴趣的:(第四章(同步并发操作))