美文网首页
第九章 基于共享变量的并发(一)竞争条件

第九章 基于共享变量的并发(一)竞争条件

作者: HaoR_W | 来源:发表于2018-01-16 14:11 被阅读0次

一、Race Condition

基本概念

并发:我们不能确定事件x和y的执行顺序,则x和y是并发的

并发(concurrent) 并行(parallel)
宏观上同时,微观上交替 微观上同时进行

线程安全(thread safety):如果在并发(多线程)的情况下,这个函数依然可以正确地工作的话,那么我们就说这个函数是线程安全的,线程安全的函数不需要额外的同步工作。

竞争条件(race condition):描述一个系统或者进程的输出依赖于不受控制的事件(如并发的x和y)出现顺序或者出现时机。

数据竞争:两个不同线程中的指令访问同一块内存位置,且至少其中一条是写指令,同时不存在同步措施来保证两条指令的执行顺序。

A data race occurs when 2 instructions from different threads access the same memory location, at least one of these accesses is a write and there is no synchronization that is mandating any particular order among these accesses.

来源: stackoverflow

拓展阅读:CAS和SAS问题(原子操作相关)

比较并交换(compare and swap) wiki
ABA问题 wiki

二、避免数据竞争

1. 使用不可变(immutable)变量

即在程序初始化时便将变量的值确定下来且不再修改
优点:初始化完成后不需要同步就能实现并发安全
缺点:不可修改

2. 使用绑定(confinement)避免从多个goroutine访问变量

(1) 使用监控goroutine(monitor goroutine)

同一个goroutine内部的指令的顺序是可知的,故使用单独的goroutine来访问某一变量,其他需要访问该变量的goroutine通过channel向该goroutine发送请求来查询或更新——“不要使用共享数据来通信;使用通信来共享数据”。执行访问请求的goroutine被称为这个变量的监控(monitor)goroutine

// Package bank provides a concurrency-safe bank with one account.
package bank

var deposits = make(chan int) // send amount to deposit
var balances = make(chan int) // receive balance

// Deposit() 和 Balance() 只使用channel来与teller() 通信,实际访问和修改操作是由teller() 来执行
func Deposit(amount int) { deposits <- amount }
func Balance() int       { return <-balances }

func teller() {
    var balance int // balance is confined to teller goroutine
    for {
        // select 语句会等待某个case的条件满足,之后便跳出,故放在循环中
        select {
        case amount := <-deposits:
            balance += amount
        case balances <- balance:
        }
    }
}

func init() {
    go teller() // start the monitor goroutine
}
(2) 使用串行绑定(serial confinement)

若变量不能在其整个生命周期内被绑定到同一个goroutine,比如该变量需要在一条pipeline上的goroutines中传递,则对pipeline中的每一个goroutine,需通过channel传递该变量的地址给下一个阶段的goroutine,并保证在传递后不再直接访问该变量,则同一时刻只有一个goroutine可以访问这个变量。

type Cake struct{ state string }

func baker(cooked chan<- *Cake) {
    for {
        cake := new(Cake)
        cake.state = "cooked"
        cooked <- cake // baker never touches this cake again
    }
}

func icer(iced chan<- *Cake, cooked <-chan *Cake) {
    for cake := range cooked {
        cake.state = "iced"
        iced <- cake // icer never touches this cake again
    }
}

3. 保证goroutines访问变量时的互斥(mutual exclusion)

允许多个goroutine访问变量,但是确保在同一个时刻最多只有一个goroutine在访问。一般使用锁来实现,在《第九章 基于共享变量的并发(三)锁》中详细讨论。





1/15/2018

相关文章

  • 第九章 基于共享变量的并发(一)竞争条件

    一、Race Condition 基本概念 并发:我们不能确定事件x和y的执行顺序,则x和y是并发的 线程安全(t...

  • Java如何写出高效的并发程序

    在Java语言里,面向对象思想能够让并发编程变得更简单。 可以从风中共享变量,识别共享变量间的约束条件和执行并发访...

  • 网络安全知识培训学习笔记

    逻辑漏洞 条件竞争 多个线程竞争同一个共享代码、变量、文件等称之为条件竞争。那么什么情况存在竞争条件? 实例:上传...

  • 共享数据和线程

    共享数据带来的问题 条件竞争 条件竞争产生 并发中竞争条件的形成,取决于一个以上线程的相对执行顺序,每个线程都抢着...

  • Go基于共享变量的并发

    Go基于共享变量的并发https://blog.csdn.net/qq_31179577/article/deta...

  • ThreadLocal模式

    多个线程同时读写同一个共享变量存在并发问题。其实可以突破共享变量,没有共享变量就不会有并发问题。没有共享,就没有伤...

  • 【Golang】通道channel

    Java的并发:基于线程Golang的并发:基于协程goroutine 并发会导致资源竞争:加锁防止资源竞争的三种...

  • Immutability模式

    多线程同时读写一共享变量存在并发问题,这里的必要条件之一是读写,如果只有读,而没有写,是没有并发问题的。 解决并发...

  • 条件竞争漏洞

    条件竞争是沃特? 敲黑板,定义:竞争条件发生在多个线程同时访问同一个共享代码、变量、文件等没有进行锁操作或者同步操...

  • Java 通过 Lock 和 竞争条件 Condition 实现

    竞争条件 多个线程共享对某些变量的访问,其最后结果取决于哪个线程偶然在竞争中获胜。 condition.await...

网友评论

      本文标题:第九章 基于共享变量的并发(一)竞争条件

      本文链接:https://www.haomeiwen.com/subject/qudsoxtx.html