【C++11】 线程库的使用(二)

简介: 【C++11】 线程库的使用(二)

3 原子操作

C++11中引入了原子操作。所谓原子操作:即不可被中断的一个或一系列操作,C++11引入的原子操作类型,使得线程间数据的同步变得非常高效。


b16a412546b64ca9af22c71b81394f4c.png👉【atomic】👈


比如之前我们抢票的代码还可以这样写:

atomic<long long> tickets;
mutex mtu;
int main()
{
  thread t1([] {
    for (int i = 0; i < 100000; ++i)
    {
      tickets++;
    }
    });
  thread t2([] {
    for (int i = 0; i < 100000; ++i)
    {
      tickets++;
    }
    });
  t1.join();
  t2.join();
  cout << tickets << endl;
  return 0;
}

运行结果:


29f2656067a442dabb3cc75807871917.png

我们使用原子操作不用加锁也可以正确的完成。其实原子操作的底层是用的CAS原子操作来完成的。

在C++11中,程序员不需要对原子类型变量进行加锁解锁操作,线程能够对原子类型变量互斥的

访问。更为普遍的,程序员可以使用atomic类模板,定义出需要的任意原子类型。

atmoic<T> t;    // 声明一个类型为T的原子类型变量t

注意:原子类型通常属于"资源型"数据,多个线程只能访问单个原子类型的拷贝,因此在C++11中,原子类型只能从其模板参数中进行构造,不允许原子类型进行拷贝构造、移动构造以及operator=等,为了防止意外,标准库已经将atmoic模板类中的拷贝构造、移动构造、赋值运算符重载默认删除掉了。

4 条件变量

先来看看condition_variable类中有哪些成员函数?

df65ec51afae44f88ba5965922eca81a.png

这个用法与Linux中基本一致,我在这里就不再多讲了。

现在假如我们要实现下面的场景,我们究竟应该怎么做?

支持两个线程交替打印,一个打印奇数,一个打印偶数

这样实现有两个注意点:

  • 1️⃣要保证一个线程先运行,一个后运行;
  • 2️⃣要防止一个线程不断运行。
  • 所以我们就可以写出下面的代码:
int num = 1;
mutex mtu;
condition_variable cdv;
int main()
{
  thread t1([=] {
    for (;num<100;num++)
    {
      unique_lock<mutex> lock(mtu);
      if (num % 2 == 0)
        cdv.wait(lock);
      cout << this_thread::get_id() << ":" << num << endl;
      cdv.notify_one();
    }
    });
  thread t2([] {
    for (; num<100; num ++)
    {
      unique_lock<mutex> lock(mtu);
      if(num%2!=0)
        cdv.wait(lock);
      cout << this_thread::get_id() << ":" << num << endl;
      cdv.notify_one();
    }
    });
  t1.join();
  t2.join();
  return 0;
}

但是上面的代码可能会存在着问题,因为在条件判断的时候我们没有加锁,这就导致有可能其中一个线程打印出了101这样的数据,所以我们可以写一个死循环,在循环体里面判断即可。

thread t1([=] {
    for (; ;num++)
    {
      unique_lock<mutex> lock(mtu);
      if (num >= 100) break;
      if (num % 2 == 0)
        cdv.wait(lock);
      cout << this_thread::get_id() << ":" << num << endl;
      cdv.notify_one();
    }
    });
  thread t2([] {
    for (; ; num++)
    {
      unique_lock<mutex> lock(mtu);
      if (num > 100)  break;
      if(num%2!=0)
        cdv.wait(lock);
      cout << this_thread::get_id() << ":" << num << endl;
      cdv.notify_one();
    }
    });


目录
相关文章
|
6月前
|
API C++ Windows
Visual C++运行库、.NET Framework和DirectX运行库的作用及常见问题解决方案,涵盖MSVCP140.dll丢失、0xc000007b错误等典型故障的修复方法
本文介绍Visual C++运行库、.NET Framework和DirectX运行库的作用及常见问题解决方案,涵盖MSVCP140.dll丢失、0xc000007b错误等典型故障的修复方法,提供官方下载链接与系统修复工具使用指南。
1514 2
|
9月前
|
负载均衡 算法 安全
基于Reactor模式的高性能网络库之线程池组件设计篇
EventLoopThreadPool 是 Reactor 模式中实现“一个主线程 + 多个工作线程”的关键组件,用于高效管理多个 EventLoop 并在多核 CPU 上分担高并发 I/O 压力。通过封装 Thread 类和 EventLoopThread,实现线程创建、管理和事件循环的调度,形成线程池结构。每个 EventLoopThread 管理一个子线程与对应的 EventLoop(subloop),主线程(base loop)通过负载均衡算法将任务派发至各 subloop,从而提升系统性能与并发处理能力。
476 3
|
6月前
|
缓存 算法 程序员
C++STL底层原理:探秘标准模板库的内部机制
🌟蒋星熠Jaxonic带你深入STL底层:从容器内存管理到红黑树、哈希表,剖析迭代器、算法与分配器核心机制,揭秘C++标准库的高效设计哲学与性能优化实践。
C++STL底层原理:探秘标准模板库的内部机制
|
6月前
|
Ubuntu API C++
C++标准库、Windows API及Ubuntu API的综合应用
总之,C++标准库、Windows API和Ubuntu API的综合应用是一项挑战性较大的任务,需要开发者具备跨平台编程的深入知识和丰富经验。通过合理的架构设计和有效的工具选择,可以在不同的操作系统平台上高效地开发和部署应用程序。
264 11
|
6月前
|
IDE 编译器 开发工具
msvcp100.dll,msvcp120.dll,msvcp140.dll,Microsoft Visual C++ 2015 Redistributable,Visual C++ 运行库安装
MSVC是Windows下C/C++开发核心工具,集成编译器、链接器与调试器,配合Visual Studio使用。其运行时库(如msvcp140.dll)为程序提供基础函数支持,常因缺失导致软件无法运行。通过安装对应版本的Microsoft Visual C++ Redistributable可解决此类问题,广泛应用于桌面软件、游戏及系统级开发。
814 2
|
7月前
|
并行计算 C++ Windows
|
11月前
|
Linux 程序员 API
CentOS如何使用Pthread线程库
这就是在CentOS下使用Pthread线程库的全过程。可见,即使是复杂的并发编程,只要掌握了基本的知识与工具,就能够游刃有余。让我们积极拥抱并发编程的魅力,编写出高效且健壮的代码吧!
265 11
|
JSON C++ 数据格式
C++20 高性能基础库--兰亭集库助力开发者构建高性能应用
这次分享的主题是《高性能基础库--兰亭集库助力开发者构建高性能应用》的实践经验。主要分为三个部分: 1. 业务背景 2. 雅兰亭库架构 3. 业务优化
540 9
|
XML 网络协议 API
超级好用的C++实用库之服务包装类
通过本文对Boost.Asio、gRPC和Poco三个超级好用的C++服务包装类库的详细介绍,开发者可以根据自己的需求选择合适的库来简化开发工作,提高代码的效率和可维护性。每个库都有其独特的优势和适用场景,合理使用这些库可以极大地提升C++开发的生产力。
365 11

热门文章

最新文章

下一篇
开通oss服务