c++11新特性多线程操作实战

 更新时间:2020年09月27日 10:54:31   作者:鬼谷子com  
这篇文章主要介绍了c++11新特性多线程操作实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

c++11多线程操作

线程

thread

int main()
{
  thread t1(Test1);
  t1.join();
  thread t2(Test2);
  t2.join();
  thread t3 = t1;
  thread t4(t1);
  thread t5 = std::move(t1);
  thread t6(std::move(t1));
  return 0;
}

t3,t4创建失败,因为thread的拷贝构造和赋值运算符重载的原型是:

thread(const thread&) = delete;
thread& operator=(const thread&) = delete;

被禁用了,但是t5, t6线程是创建成功的。std::move把t1转换为右值,调用的是函数原型为thread& operator=(thread&& _Other) noexceptthread(thread&& _Other) noexcept

当线程对象t1被移动拷贝和移动赋值给t5和t6的时候,t1就失去了线程控制权,也就是一个线程只能同时被一个线程对象所控制。最直观的是t1.joinable()返回值为false,joinable()函数后面介绍。

使用类成员函数作为线程参数:

class Task
{
public:
  Task(){}
  void Task1() {}
  void Task2() {}
private:
};

int main()
{
  Task task;
  thread t3(&Task::Task1, &task);
  t3.join();
  return 0;
}

关键点是要创建一个类对象,并作为第二个参数传入thread()线程的构造函数中去。

管理当前线程的函数

yield

此函数的准确性为依赖于实现,特别是使用中的 OS 调度器机制和系统状态。例如,先进先出实时调度器( Linux 的 SCHED_FIFO )将悬挂当前线程并将它放到准备运行的同优先级线程的队列尾(而若无其他线程在同优先级,则 yield 无效果)。

#include <iostream>
#include <chrono>
#include <thread>
 
// 建议其他线程运行一小段时间的“忙睡眠”
void little_sleep(std::chrono::microseconds us)
{
  auto start = std::chrono::high_resolution_clock::now();
  auto end = start + us;
  do {
    std::this_thread::yield();
  } while (std::chrono::high_resolution_clock::now() < end);
}
 
int main()
{
  auto start = std::chrono::high_resolution_clock::now();
 
  little_sleep(std::chrono::microseconds(100));
 
  auto elapsed = std::chrono::high_resolution_clock::now() - start;
  std::cout << "waited for "
       << std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count()
       << " microseconds\n";
}

get_id

这个函数不用过多介绍了,就是用来获取当前线程id的,用来标识线程的身份。

std::thread::id this_id = std::this_thread::get_id();

sleep_for

位于this_thread命名空间下,msvc下支持两种时间参数。

std::this_thread::sleep_for(2s);
std::this_thread::sleep_for(std::chrono::seconds(1));

sleep_untile

参数构建起来挺麻烦的,一般场景下要求线程睡眠的就用sleep_for就行了

using std::chrono::system_clock;
time_t tt = system_clock::to_time_t(system_clock::now());
struct std::tm *ptm = localtime(&tt);
 std::this_thread::sleep_until(system_clock::from_time_t(mktime(ptm)));

互斥

mutex

对于互斥量看到一个很好的比喻:

单位上有一台打印机(共享数据a),你要用打印机(线程1要操作数据a),同事老王也要用打印机(线程2也要操作数据a),但是打印机同一时间只能给一个人用,此时,规定不管是谁,在用打印机之前都要向领导申请许可证(lock),用完后再向领导归还许可证(unlock),许可证总共只有一个,没有许可证的人就等着在用打印机的同事用完后才能申请许可证(阻塞,线程1lock互斥量后其他线程就无法lock,只能等线程1unlock后,其他线程才能lock),那么,这个许可证就是互斥量。互斥量保证了使用打印机这一过程不被打断。

代码示例:

mutex mtx;

int gNum = 0;
void Test1()
{
  mtx.lock();
  for(int n = 0; n < 5; ++n)
    gNum++;
  mtx.unlock();
}

void Test2()
{
  std::cout << "gNum = " << gNum << std::endl;
}

int main()
{
  thread t1(Test1);
  t1.join();
  thread t2(Test2);
  t2.join();
  return 0;
}

join()表示主线程等待子线程结束再继续执行,如果我们的期望是打印循环自增之后的gNum的值,那t1.join()就放在t2创建之前调用。因为t2的创建就标志着t2线程创建好然后开始执行了。

通常mutex不单独使用,因为lock和unlock必须配套使用,如果忘记unlock很可能造成死锁,即使unlock写了,但是如果在执行之前程序捕获到异常,也还是一样会死锁。如何解决使用mutex造成的死锁问题呢?下面介绍unique_gard和lock_guard的时候详细说明。

timed_mutex
提供互斥设施,实现有时限锁定

recursive_mutex
提供能被同一线程递归锁定的互斥设施

recursive_timed_mutex
提供能被同一线程递归锁定的互斥设施,并实现有时限锁定

通用互斥管理

lock_guard

void Test1()
{
  std::lock_guard<std::mutex> lg(mtx);
  for(int n = 0; n < 5; ++n)
  {
    gNum++;
    std::cout << "gNum = " << gNum << std::endl;
  }
}
int main()
{
  thread t1(Test1);
  thread t2(Test1);
  t1.join();
  t2.join();
  return 0;
}

lock_guard相当于利用RAII机制(“资源获取就是初始化”)把mutex封装了一下,在构造中lock,在析构中unlock。避免了中间过程出现异常导致的mutex不能够正常unlock.

  • scoped_lock(c++17)
  • unique_lock
  • defer_lock_t
  • try_to_lock_t
  • adopt_lock_t
  • defer_lock
  • try_to_lock
  • adopt_lock

通用锁算法

  • try_lock
  • lock

单次调用

  • once_flag
  • call_once

条件变量

  • condition_variable
  • condition_variable_any
  • notify_all_at_thread_exit
  • cv_status

Future

  • promise
  • packaged_task
  • future
  • shared_future
  • async
  • launch
  • future_status
  • Future错误
    • future_error
    • future_category
    • future_errc

到此这篇关于c++11新特性多线程操作实战的文章就介绍到这了,更多相关c++11 多线程操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言中实现itoa函数的实例

    C语言中实现itoa函数的实例

    这篇文章主要介绍了C语言中实现itoa函数的实例的相关资料,希望通过本文能帮助到大家,让大家实现这样的功能,需要的朋友可以参考下
    2017-10-10
  • C语言中设置用户识别码的相关函数的简单讲解

    C语言中设置用户识别码的相关函数的简单讲解

    这篇文章主要介绍了C语言中设置用户识别码的相关函数的简单讲解,包括setuid()函数和setreuid()函数以及setfsuid()函数,需要的朋友可以参考下
    2015-08-08
  • C语言选择排序算法及实例代码

    C语言选择排序算法及实例代码

    本篇文章主要介绍了 C语言选择排序算法,这里提供代码实例以便大家理解,通过本文,更好的理解排序算法
    2016-07-07
  • c++ 数字类型和字符串类型互转详解

    c++ 数字类型和字符串类型互转详解

    今天小编就为大家分享一篇讲解c++ 数字类型和字符串类型互转的文章,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-09-09
  • C语言排序算法之冒泡排序实现方法【改进版】

    C语言排序算法之冒泡排序实现方法【改进版】

    这篇文章主要介绍了C语言排序算法之冒泡排序实现方法,结合具体实例形式分析了C语言实现的基本冒泡排序实现方法及增设flag标志位的改进型算法,需要的朋友可以参考下
    2017-09-09
  • 深入理解QT多线程编程

    深入理解QT多线程编程

    本文主要介绍了QT多线程编程的深入理解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-06-06
  • 提高C程序效率的10种有效方法

    提高C程序效率的10种有效方法

    本文向你介绍规范你的C代码的10种方法。需要的朋友可以过来参考下,希望对大家有所帮助
    2013-10-10
  • 详解C语言中的错误报告errno与其相关应用方法

    详解C语言中的错误报告errno与其相关应用方法

    这篇文章主要介绍了C语言中的错误报告errno与其相关应用方法,包括errno和strerror以及perror的介绍,需要的朋友可以参考下
    2015-08-08
  • C/C++ Qt QChart绘图组件的具体使用

    C/C++ Qt QChart绘图组件的具体使用

    QtCharts 组件是QT中提供图表绘制的模块,用来绘制常规图形,本文就详细的介绍了QChart的使用,以及柱状图,折线图等常用的图形的实现,感兴趣的可以了解一下
    2021-11-11
  • C++ 智能指针的魅力你都了解吗

    C++ 智能指针的魅力你都了解吗

    智能指针使用和普通指针类似。解引用一个智能指针返回它指向的对象。如果在一个条件判断中使用智能指针,效果就是检测它是否为空,本文给大家介绍C++ 智能指针的相关知识,感兴趣的朋友一起看看吧
    2021-06-06

最新评论