Xander's Wiki


  • Home

  • Tags

  • Categories

  • Archives

  • Search

同步并发操作——限制等待时间

Posted on 2019-05-07 | In C++并发编程实战

前言

 
在本章前文所述的各项等待操作中,线程阻塞的时间并不确定,但在实际应用中存在这样的需求:限制线程等待时间——在线程等待特定的一段时间后,开发者既可以向用户发出“该事件仍未完成”的提示,也可以接受由于用户放弃等待从而关闭线程的命令。

判断程序运行超时有两种方式:

  1. duration-based
    该方式需要用户指定一段时间,例如30ms。
  2. absolute
    该方式需要用户提供一个时间点,例如17:30:15.045987023 UTC on November 30, 2011。

大多数等待函数均支持这两种方式,处理duration-based的后缀为_for,处理absolute的后缀为_until。举例而言,std::condition_variable的成员函数wait_for()和wait_until()。此外,这些函数具备2种重载,第一种重载形式等待着信号触发或虚假唤醒,另一种则在唤醒时检查谓词,并仅在结果为true的情况下返回,或直接超时返回。更多相关信息可见本节末尾的图表。

Read more »

同步并发操作——使用future等待一次性事件

Posted on 2019-04-21 | In C++并发编程实战

前言

 
本节我们将讨论线程应当以何种方式处理一次性事件,即线程仅需要被notice一次。

Read more »

同步并发操作——等待事件或条件

Posted on 2019-04-20 | In C++并发编程实战

前言

 
在线程运行过程中经常发生如下场景:线程A需要等待线程B完成某操作。有三种方案可以解决这一需求:

  1. 反复检查共享标志位(例如mutex),直到某线程完成操作后将其置位。
    这将造成两点浪费:首先,线程不得不耗费宝贵的运行时间循环检查数据;其次,如果mutex被线程A上锁(它需要锁住互斥量以查看被其保护的标志位),那么其他线程将无法获得该锁,甚至连已完成任务的线程B也无法锁住互斥量以重置该标志位。

  2. 使用std::this_thread::sleep_for()令线程在等待间隙短暂休眠

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    bool flag; 
    std::mutex m;
    void wait_for_flag() {
    std::unique_lock<std::mutex> lk(m);
    while(!flag) {
    lk.unlock();
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 休眠100ms
    //....此时可以保证其他线程获取该锁,重置flag
    lk.lock();
    }
    }

    方案2优于方案1,但缺憾在于开发者无法确定休眠时间取多少合适。过少的休眠时间等于没有,过多的休眠时间又会造成任务必须等待线程苏醒。尽管休眠时间过长很少会对程序运行产生直接影响,但在对实时性较高的场景中(例如游戏画面绘制),这意味着一场灾难。

  3. 使用C++标准库提供的工具
    最基本的处理等待事件机制为条件变量(condition variable)。从本质而言,条件变量的存在与事件或条件相关联,并且必须存在一些等待该变量被满足的线程。若当前执行线程确定条件已被满足,那么它将通知一个或多个等待该条件变量被满足的线程,以便唤醒它们接着执行任务。

Read more »

线程间共享数据——保护共享数据的替代设施

Posted on 2019-04-17 | In C++并发编程实战

前言

 
保护共享数据并非只有互斥量一种机制(尽管它是最通用的),有很多替代方案可以在特定情况下提供比互斥量更合适的保护。

Read more »

线程间共享数据——使用互斥量保护共享数据

Posted on 2019-04-16 | In C++并发编程实战

前言

 
在C++并发编程中,保护共享数据最简单的方法是使用互斥量。

在访问共享数据前,开发者可使用互斥量将相关数据锁住,并于访问结束后将数据解锁。因此,线程库需要保证当一个线程使用特定互斥量锁住共享数据时,其他线程仅可在数据被解锁后才能访问。

互斥量是C++中最通用的一种数据保护机制,但它并非“银弹”,在使用互斥量时,需要精心组织代码来保护正确的数据,并在接口内部避免竞争条件。此外,互斥量自身存在一定的问题,它可能会导致死锁,又或者将某些数据保护地太多或者太少。下文将针对上述情况逐一作出分析。

Read more »

线程间共享数据——共享数据导致的问题

Posted on 2019-04-09 | In C++并发编程实战

前言

 
并发编程中的大多数数据问题都起因于共享数据被多个线程修改,读取只读属性的共享数据不会存在任何问题。

Read more »

线程管理——运行期决定线程数量

Posted on 2019-04-08 | In C++并发编程实战

hardware_concurrency

 
C++标准库提供了名为std::thread::hardware_concurrency()的函数,该函数将返回能同时并发在一个程序中的线程数量。举例而言,在多核系统返回值为CPU核芯数量;在无法获取系统信息时,该值为0。显然,该API是在运行期决定线程数量的重要提示。

Read more »

线程管理——转移线程所有权

Posted on 2019-04-08 | In C++并发编程实战

前言

 
在上一节中我们已经提及std::thread对象是一个move only object,而move的过程也正是转移线程所有权的过程。本节将对如何转移线程所有权,以及转移线程所有权的实际应用场景作出简单介绍。

Read more »

线程管理——向线程函数传递参数

Posted on 2019-04-07 | In C++并发编程实战

前言

 
在上一节中,所有的入口函数均为无参函数,若某个入口函数存在形参,则需要向线程函数传递参数。这一行为并不复杂,仅仅需要在函数名后加上参数即可,例如:

1
2
void do_some_work(int); 
std::thread my_thread(do_some_work,5);
Read more »

线程管理——线程管理基础

Posted on 2019-04-07 | In C++并发编程实战

前言

 
每一个程序都至少存在一个线程:执行main函数的原始线程,其余线程与原始线程同时运行(并非同时启动),并在执行完其入口函数后退出。本节将从如何启动线程说起,大致地为读者介绍C++并发编程中的线程管理基础。

Read more »
<i class="fa fa-angle-left"></i>1234…27<i class="fa fa-angle-right"></i>

xander.liu

266 posts
11 categories
36 tags
RSS
GitHub E-Mail
© 2024 xander.liu
Powered by Hexo
|
Theme — NexT.Pisces v5.1.4