C++11标准在标准库中为多线程提供了组件,这意味着使用C++编写与平台无关的多线程程序成为可能,而C++程序的可移植性也得到了有力的保证。另外,并发编程可提高应用的性能,这对对性能锱铢必较的C++程序员来说是值得关注的。

1. 何为并发

并发指的是两个或多个独立的活动在同一时段内发生。生活中并发的例子并不少,例如在跑步的时候你可能同时在听音乐;在看电脑显示器的同时你的手指在敲击键盘。这时我们称我们大脑并发地处理这些事件,只不过我们大脑的处理是有次重点的:有时候你会更关注你呼吸的频率,而有时候你更多地被美妙的音乐旋律所吸引。这时我们可以说大脑是一种并发设计的结构。这种次重点在计算机程序设计中,体现为某一个时刻只能处理一个操作。

与并发相近的另一个概念是并行。它们两者存在很大的差别。并行就是同时执行,计算机在同一时刻,在某个时间点上处理两个或以上的操作。判断一个程序是否并行执行,只需要看某个时刻上是否多两个或以上的工作单位在运行。一个程序如果是单线程的,那么它无法并行地运行。利用多线程与多进程可以使得计算机并行地处理程序(当然 ,前提是该计算机有多个处理核心)。

  • 并发:同一时间段内可以交替处理多个操作:

图中整个安检系统是一个并发设计的结构。两个安检队列队首的人竞争这一个安检窗口,两个队列可能约定交替着进行安检,也可能是大家同时竞争安检窗口(通信)。后一种方式可能引起冲突:因为无法同时进行两个安检操作。在逻辑上看来,这个安检窗口是同时处理这两个队列。

  • 并行:同一时刻内同时处理多个操作:

图中整个安检系统是一个并行的系统。在这里,每个队列都有自己的安检窗口,两个队列中间没有竞争关系,队列中的某个排队者只需等待队列前面的人安检完成,然后再轮到自己安检。在物理上,安检窗口同时处理这两个队列。

并发的程序设计,提供了一种方式让我们能够设计出一种方案将问题(非必须地)并行地解决。如果我们将程序的结构设计为可以并发执行的,那么在支持并行的机器上,我们可以将程序并行地执行。因此,并发重点指的是程序的设计结构,而并行指的是程序运行的状态。并发编程,是一种将一个程序分解成小片段独立执行的程序设计方法。

2.并发的基本方式途径

多线程与多进程是并发的两种途径。
想象两个场景:

  • 场景一:你和小伙伴要开发一个项目,但小伙伴们放寒假都回家了,你们只能通过QQ聊天、手机通话、发送思维导图等方式来进行交流,总之你们无法很方便地进行沟通。好处是你们各自工作时可以互不打扰。
  • 场景二:你和小伙伴放假都呆在学校实验室中开发项目,你们可以聚在一起使用头脑风暴,可以使用白板进行观点的阐述,总之你们沟通变得更方便有效了。有点遗憾的是你在思考时可能有小伙伴过来问你问题,你受到了打扰。

这两个场景描绘了并发的两种基本途径。每个小伙伴代表一个线程,工作地点代表一个处理器。场景一中每个小伙伴是一个单线程的进程,他们拥有独立的处理器,多个进程同时执行;场景二中只有一个处理器,所有小伙伴都是属于同一进程的线程。

2.1 多进程并发

多个进程独立地运行,它们之间通过进程间常规的通信渠道传递讯息(信号,套接字,文件,管道等),这种进程间通信不是设置复杂就是速度慢,这是因为为了避免一个进程去修改另一个进程,操作系统在进程间提供了一定的保护措施,当然,这也使得编写安全的并发代码更容易。
运行多个进程也需要固定的开销:进程的启动时间,进程管理的资源消耗。

2.2 多线程并发

在当个进程中运行多个线程也可以并发。线程就像轻量级的进程,每个线程相互独立运行,但它们共享地址空间,所有线程访问到的大部分数据如指针、对象引用或其他数据可以在线程之间进行传递,它们都可以访问全局变量。进程之间通常共享内存,但这种共享通常难以建立且难以管理,缺少线程间数据的保护。因此,在多线程编程中,我们必须确保每个线程锁访问到的数据是一致的。

3. C++中的并发与多线程

C++标准并没有提供对多进程并发的原生支持,所以C++的多进程并发要靠其他API——这需要依赖相关平台。
C++11 标准提供了一个新的线程库,内容包括了管理线程、保护共享数据、线程间的同步操作、低级原子操作等各种类。标准极大地提高了程序的可移植性,以前的多线程依赖于具体的平台,而现在有了统一的接口进行实现。

C++11 新标准中引入了几个头文件来支持多线程编程:(所以我们可以不再使用 CreateThread 来创建线程,简简单单地使用 std::thread 即可。)

  • < thread > :包含std::thread类以及std::this_thread命名空间。管理线程的函数和类在 中声明.
  • < atomic > :包含std::atomic和std::atomic_flag类,以及一套C风格的原子类型和与C兼容的原子操作的函数。
  • < mutex > :包含了与互斥量相关的类以及其他类型和函数
  • < future > :包含两个Provider类(std::promise和std::package_task)和两个Future类(std::future和std::shared_future)以及相关的类型和函数。
  • < condition_variable > :包含与条件变量相关的类,包括std::condition_variable和std::condition_variable_any。

3.1 初试多线程

  1、主进程等待子线程

  

#include <iostream>
#include <thread>
#include <Windows.h> using namespace std; void thread01()
{
for (int i = 0; i < 5; i++)
{
cout << "Thread 01 is working !" << endl;
Sleep(100);
}
}
void thread02()
{
for (int i = 0; i < 5; i++)
{
cout << "Thread 02 is working !" << endl;
Sleep(200);
}
} int main()
{
thread task01(thread01);
thread task02(thread02);
task01.join();
task02.join(); for (int i = 0; i < 5; i++)
{
cout << "Main thread is working !" << endl;
Sleep(200);
}
system("pause");
}

  2.主进程和子进程互不干扰

  

#include <iostream>
#include <thread>
#include <Windows.h> using namespace std; void thread01()
{
for (int i = 0; i < 5; i++)
{
cout << "Thread 01 is working !" << endl;
Sleep(100);
}
}
void thread02()
{
for (int i = 0; i < 5; i++)
{
cout << "Thread 02 is working !" << endl;
Sleep(200);
}
} int main()
{
thread task01(thread01);
thread task02(thread02);
task01.detach();
task02.detach(); for (int i = 0; i < 5; i++)
{
cout << "Main thread is working !" << endl;
Sleep(200);
}
system("pause");
}

  3.带参数的子线程

#include <iostream>
#include <thread>
#include <Windows.h> using namespace std; //定义带参数子线程
void thread01(int num)
{
for (int i = 0; i < num; i++)
{
cout << "Thread 01 is working !" << endl;
Sleep(100);
}
}
void thread02(int num)
{
for (int i = 0; i < num; i++)
{
cout << "Thread 02 is working !" << endl;
Sleep(200);
}
} int main()
{
thread task01(thread01, 5); //带参数子线程
thread task02(thread02, 5);
task01.detach();
task02.detach(); for (int i = 0; i < 5; i++)
{
cout << "Main thread is working !" << endl;
Sleep(200);
}
system("pause");
}

  4.多线程竞争的情况

有两个问题,一是有很多变量被重复输出了,而有的变量没有被输出;二是正常情况下每个线程输出的数据后应该紧跟一个换行符,但这里大部分却是另一个线程的输出。

这是由于第一个线程对变量操作的过程中,第二个线程也对同一个变量进行各操作,导致第一个线程处理完后的输出有可能是线程二操作的结果。针对这种数据竞争的情况,可以使用线程互斥对象mutex保持数据同步。

mutex类的使用需要包含头文件mutex:

#include <iostream>
#include <thread>
#include <Windows.h>
#include <mutex> using namespace std; mutex mu; //线程互斥对象 int totalNum = 100; void thread01()
{
while (totalNum > 0)
{
mu.lock(); //同步数据锁
cout << totalNum << endl;
totalNum--;
Sleep(100);
mu.unlock(); //解除锁定
}
}
void thread02()
{
while (totalNum > 0)
{
mu.lock();
cout << totalNum << endl;
totalNum--;
Sleep(100);
mu.unlock();
}
} int main()
{
thread task01(thread01);
thread task02(thread02);
task01.detach();
task02.detach();
system("pause");
}

  

3.2 在类中使用子线程的一个问题

  当我们再类中使用子线程我们会发现,我们不能把初始函数设置为类的成员函数,必须要把成员函数设置成static类型的才可以,但是这有设计到一个问题,就是static的类成员函数不能调用非static的变量成员,下面是一个两全其美的方法:

thread sendtask(bind(&client::sendata, this));//其中client是类的名字

  这样就可以解决我们的问题。

c++的并发操作(多线程)的更多相关文章

  1. 第五十四节,socketserver通讯模块实现并发操作,真多线程并发

    socketserver通讯模块实现并发操作,基于select.epoll.socket.多线程,实现的正真多线程多并发 socketserver通讯模块底层调用的socket模块,只是它作了处理基于 ...

  2. SQLite多线程下的并发操作

    标签: sqlite多线程数据库跨平台嵌入式class 2011-04-14 13:29 26939人阅读 评论(2) 收藏 举报 这两天一直在捣鼓SQLite数据库,基本的操作就不说了,比较简单,打 ...

  3. python多进程并发和多线程并发和协程

    为什么需要并发编程? 如果程序中包含I/O操作,程序会有很高的延迟,CPU会处于等待状态,这样会浪费系统资源,浪费时间 1.Python的并发编程分为多进程并发和多线程并发 多进程并发:运行多个独立的 ...

  4. Java多线程学习(一)---并发与多线程

    Java并发与多线程 摘要: 1. 并发与并行的区别,何为并发编程,并发编程的优势在哪 2. 多线程.多任务.多进程机制概述 3. 多线程.多任务.多进程机制与编程思想的关系 一.并发 1.1 并发与 ...

  5. 并发和多线程-八面玲珑的synchronized

    上篇<并发和多线程-说说面试常考平时少用的volatile>主要介绍的是volatile的可见性.原子性等特性,同时也通过一些实例简单与synchronized做了对比. 相比较volat ...

  6. python高并发和多线程的关系

    “高并发和多线程”总是被一起提起,给人感觉两者好像相等,实则 高并发 ≠ 多线程 多线程是完成任务的一种方法,高并发是系统运行的一种状态,通过多线程有助于系统承受高并发状态的实现.   高并发是一种系 ...

  7. php-fpm和cgi,并发响应的理解以及高并发和多线程的关系

    首先搞清楚php-fpm与cgi的关系 cgi cgi是一个web server与cgi程序(这里可以理解为是php解释器)之间进行数据传输的协议,保证了传递的是标准数据. php-cgi php-c ...

  8. Java并发和多线程:序

      近期,和不少公司的"大牛"聊了聊,当中非常多是关于"并发和多线程"."系统架构"."分布式"等方面内容的.不少问题, ...

  9. Java并发基础--多线程基础

    一.多线程基础知识 1.进程和线程 进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程:进程也是程序的一次执行过程,是系统运行程序的基本单位:系统运行 ...

随机推荐

  1. CentOS(Oracle_Linux)系统网卡配置文件参数详解

    Each physical and virtual network device on an Oracle Linux system has an associated configuration f ...

  2. Sublime Text3学习参考集

    1.如何优雅地使用Sublime Text: http://jeffjade.com/2015/12/15/2015-04-17-toss-sublime-text/#three 持续更新中..... ...

  3. Xcode8.1 真机测试 ,添加iOS10.3的idk到Xcode8.1中

    1.下载iOS10.3的idk包; 2.解压, 找到路径 Finder -> 应用程序 -> 右键Xcode -> 显示包内容 -> Contents -> Develo ...

  4. k8s1.11.0安装、一个master、一个node、查看node名称是ip、node是扩容进来的、带cadvisor监控服务

    一个master.一个node.查看node节点是ip # 安装顺序:先在test1 上安装完必要组件后,就开始在 test2 上单独安装node组件,实现node功能,再返回来配置test1加入集群 ...

  5. 重启 hdfs and yarn datanode

    1- start-all.sh and stop-all.sh: Used to start and stop hadoop daemons all at once. Issuing it on th ...

  6. Element Children

    The childNodes property contains all of the immediate children of the element. There is a significan ...

  7. Sqlserver实现故障转移 — AlwaysOn实现故障转移(4)

    目的:在已经加域的计算机上安装sqlserver2012,并配置系统级故障转移及数据库,实现AlwayOn. 域控的建立详见:https://www.cnblogs.com/xiaoerlang90/ ...

  8. Golang 单例模式 singleton pattern

    在Java中,单例模式的实现主要依靠类中的静态字段.在Go语言中,没有静态类成员,所以我们使用的包访问机制和函数来提供类似的功能.来看下下面的例子: package singleton         ...

  9. PJzhang:crunch,一个很好的字典生成工具

    猫宁!!! 之前收集子域名的时候使用过子域名挖掘机这个windows软件,查看了它所使用的字典,基本上是小写字母数字1-4位的一个合集.   36+36*36+36*36*36+36*36*36*36 ...

  10. 5分钟学会maven入门

    一.背景 1.定位:Maven是优秀的构建工具 2.意义:自动化构建,即节约了我们每天有相当一部分时间花在编 译.运行单元测试.生成文档.打包和部署等烦琐且不起眼的时间. 3.三要素:目标(Targe ...