1.6 众人拾柴火焰高(2)

多线程程序处于一个多变的环境当中,可访问的全局变量和堆数据随时都可能被其他的线程改变。因此多线程程序在并发时数据的一致性变得非常重要。

两个线程同时读写同一个共享数据会导致意想不到的后果。

自增(++)操作在多线程环境下会出现错误是因为这个操作被编译为汇编代码之后不止一条指令,因此在执行的时候可能执行到了一半就被调度系统打断,去执行别的代码。我们把单指令的操作称为原子的。

Windows Interlocked API

InterLockedExchange

InterLockedDecrement

InterLockedIncrement

InterLockedXor

原子操作指令非常方便,但它们仅适用于比较简单特定的场合,在复杂场合下,我们需要更加通用的手段:锁。

我们需要将各个线程对同一个数据的访问同步。所谓同步,即指一个线程访问数据未结束的时候,其他线程不得对同一个数据进行访问,数据的访问被原子化了。

同步最常用的方法是使用锁,锁是一种非强制机制,访问数据之前首先尝试获取锁,并在访问之后释放锁,在锁已经被占用的情况下试图获取锁时,线程会等待。

二元信号量,多元信号量简称信号量(Semaphore),初始值为N,可以允许N个线程访问。

互斥量(Mutex)获取的线程需要负责释放,而信号量可以被一个线程获取之后由另一个线程释放。

临界区(Critical Section)作用范围仅限于进程内。

读写锁(Read-Lock Lock):

读写锁状态                         以共享方式获取                         以独占方式获取

自由                                    成功                                            成功

共享                                    成功                                            等待

独占                                    等待                                            等待

条件变量(Condition Variable)线程可以等待条件变量,一个条件变量可以被一个或多个线程等待。其次,线程可以唤醒条件变量,此时所有等待条件变量的线程都恢复执行。

一个函数被称为可重入的,表明该函数被重入之后不会产生任何不良后果。

函数可重入的特点:

不使用任何(局部)静态或全局的非const变量。

不使用任何(局部)静态或全局的非const变量的指针。

仅依赖于调用方提供的参数。

不依赖任何单个资源的锁(mutex等)。

不调用任何不可重入的函数。

我们可以使用volatile关键字阻止编译器过度优化,volatile基本可以做到两件事:

阻止编译器为了提高速度将一个变量缓存到寄存器内而不写回。

阻止编译器调整操作volatile变量的指令顺序。

barrier指令阻止CPU交换指令的顺序。

您还未添加分享代码,请到主题选项中,添加百度分享代码!

您可以选择一种方式赞助本站

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

图片 表情