CC++并发编程(1)——并发并⾏、多线程内存模型
最近看了《七周七并发模型》,对⾃⼰熟悉的C/C++并发编程有了很多新的思考。在Google上搜索“C C++ 并发 编程”,结果主要是
Anthony的《C++ Concurrency in Action》以及零散的⼀些博⽂。Anthony的书主要是教授C++最基础的线程与锁模型和⽆锁编程的知识,但是其它的并发模型书中并未提及。线程与锁模型因其资料丰富“简单易学”被⼴⼤C/C++程序员所使⽤。该模型导致的死锁、饥饿等等问题也是⼤家很头痛的事情。实际上对于C/C++并发模型,我们还有很多其它的选择,⽐如Actor、CSP、协程等,⽽这正是这个C/++并发编程系列要告诉⼤家的。开篇先说⼀下并发编程的基础知识,并发与并⾏的区别和C/C++多线程内存模型。
并发与并⾏的区别?
⽹络上有很多关于“并发”与“并⾏”的解释,⼤家⽐较认同的是Golang⼤神Rob Pike在“并发不是并⾏”的技术分享上的解释:
Concurrency vs. parallelism
Concurrency is about dealing with lots of things at once.
Parallelism is about doing lots of things at once.
vs编程软件
Not the same, but related.
Concurrency is about structure, parallelism is about execution.并发关乎结构,并⾏关乎执⾏。
Concurrency provides a way to structure a solution to solve a problem that may (but not necessarily) be
parallelizable.并发提供了⼀种⽅式让我们能够设计⼀种⽅案将问题(⾮必须的)并⾏的解决。按我个⼈对以上的理解,“并⾏”和“并发”的区别,可以简单理解为“并⾏ = 并发执⾏”。不管是多线程程序、多进程程序,在设计和实现阶段应该称之为“并发”,⽽运⾏时应该称之为“并⾏”。可以类⽐我们熟悉的“程序 vs. 进程”,运⾏时的程序称之为进程。它们都是对同⼀个事物处在不同阶段/状态时的定义。
C/C++多线程内存模型
以前我认为内存模型和内存布局是⼀回事,⽐如Linux下ELF可执⾏⽂件格式,堆、栈、.data段、.text段等等。实际上ELF这样的内存布局格式是Linux操作系统对可执⾏程序的规范,不管⽤什么编程语⾔⽣成了直接(依赖运⾏时“虚拟机”的语⾔除外)可运⾏的程序,最终都是ELF的内存布局。⽽内存模型是编程语⾔和计算机系统(包括编译器,多核CPU等可能对程序进⾏乱序优化的软硬件)之间的契约,它规定了多个线程访问同⼀个内存位置时的语义,以及某个线程对内存位置的更新何时能被其它线程看见。
在C11/C++11标准之前,C/C++语⾔没有内存模型的定义。在此期间,我们天真的认为程序是按顺序⼀致性(Sequential consistency)模型去运⾏的,⽽实际上编译器和多核CPU却是不满⾜顺序⼀致性模型的。Leslie在其论⽂中定义了顺序⼀致性模型需要满⾜的两个条件:
Rl: Each processor issues memory requests in the order specified by its program.
R2: Memory requests from all processors issued to an individual memory module are serviced from a
single FIFO queue. Issuing a memory request consists of entering the request on this queue.
条件“R1”可以理解为“单个线程内指令的执⾏顺序和代码的顺序是⼀致的”,⽽条件“R2”则让多线程的指令执⾏顺序从全局来看是“串⾏”执⾏的。现代CPU的缓存、流⽔线和乱序执⾏机制以及编译器的代码优化、重排都⽆法满⾜顺序⼀致性模型。所以,机器实际执⾏的代码并不是你写的代码。
[1][3][2]
[4][6][9]

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。