Pellucid stm

17
SOFTWARE TRANSACTIONAL MEMORY @DUSTINWHITNEY

description

Lightning Talk on Software Transactional Memory in Scala. The Actors Pattern has gotten a lot of attention in the Scala ecosphere, but STM of often a good first solution for solving concurrency problems. It's odd that it hasn't had as much attention in the Scala world, so this talk aims to show how easy it is to use, and compare it to typical lock-based synchronization by showing how easy it is to make errors with lock-based synchronization

Transcript of Pellucid stm

Page 1: Pellucid stm

SOFTWARE TRANSACTIONAL MEMORY@DUSTINWHITNEY

Page 2: Pellucid stm

Alternative to lock-based synchronization

Analogous to database transactions

ACI (ACID with out the ‘D’)

Simple! (well… simplier)

WHAT IS STM?

Page 3: Pellucid stm

libraryDependencies += ("org.scala-stm" %% "scala-stm" %

"0.7")

import scala.concurrent.stm._

val protectedInt = Ref(0)

atomic{ implicit transaction=> val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

WHAT DOES IT LOOK LIKE?

Page 4: Pellucid stm

ATOMIC

val protectedInt = Ref(0)val anotherProtectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1) val anotherCurrentValue = anotherProtectedInt.get anotherProtectedInt.set(anotherCurrentValue + 1)}

Page 5: Pellucid stm

CONSISTENT

val protectedInt = Ref(0)

atomic{ transaction => val currentValue = protectedInt.get(transaction) protectedInt.set(currentValue + 1)(transaction)}

Page 6: Pellucid stm

val protectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

ISOLATED

Page 7: Pellucid stm

STM is not Durable

DURABLE

Page 8: Pellucid stm

ADVANTAGES: DEADLOCK / LIVELOCK

val protectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

Page 9: Pellucid stm

ADVANTAGES: PRIORITY INVERSION

val protectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

Page 10: Pellucid stm

ADVANTAGES: COMPOSABILITY

val protectedInt = Ref(0)val anotherProtedtedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1) atomic{ implicit transaction => val anotherCurrentValue = anotherProtectedInt.get val anotherProctedInt.set(anotherCurrentValue + 1) }

}

Page 11: Pellucid stm

GOTCHAS: IMMUTABILITY!

// bad!val badMap= Ref(new java.util.HashMap[String, Int]())val mutableMap = atomic{ implicit transaction => badMap.get }mutableMap.put(“Wrong!”, 666)

// goodval goodMap = Ref(Map(“Good” -> 7))atomic{ implicit transaction => val tempMap = goodMap.get goodMap.set(tempMap + (“Good” -> 777))}

Page 12: Pellucid stm

GOTCHAS: REFERENTIAL TRANSPARENCY

//badval protectedString = Ref("This is a string")val time = System.currentTimeMillisatomic{ implicit transaction => if(time % 2 == 0) protectedString.set("Time was even") else protectedString.set("Time was odd")}

//goodatomic{ implicit transaction => val time = System.currentTimeMillis if(time % 2 == 0) protectedString.set("Time was even") else protectedString.set("Time was odd")}

Page 13: Pellucid stm

EXTENDED EXAMPLE: STM

case class Account(number: Int, balance: Int)

val accounts = Ref(Map( 1 -> Account(1, 100), 2 -> Account(2, 100) ))

def transfer(to: Int, from: Int, amount: Int){ atomic{ implicit transaction => val map = accounts.get val toAccount = map(to) val fromAccount = map(from) accounts.set( map + (to -> (toAccount.copy(balance = toAccount.balance + amount))) + (from -> (fromAccount.copy(balance = fromAccount.balance - amount))) ) } }

Page 14: Pellucid stm

EXTENDED EXAMPLE: SYNCHRONIZED

import java.util._private val accounts = new HashMap[Int, Account]()accounts.put(1, Account(1, 100))accounts.put(2, Account(2, 100))

def transfer(to: Int, from: Int, amount: Int){ accounts.synchronized{ val toAccount = accounts.get(to) val fromAccount = accounts.get(from) accounts.put(to, (toAccount.copy(balance = toAccount.balance + amount))) accounts.put(from, (fromAccount.copy(balance = fromAccount.balance - amount))) }}

Page 15: Pellucid stm

EXTENDED EXAMPLE: SYNCHRONIZED2

import java.util.concurrent._private val accounts = ConcurrentHashMap[Int, Account]()accounts.put(1, Account(1, 100))accounts.put(2, Account(2, 100))

def transfer(to: Int, from: Int, amount: Int){ val toAccount = accounts.get(to) val fromAccount = accounts.get(from) toAccount.synchronized{ fromAccount.synchronized{ accounts.put(to, (toAccount.copy(balance = toAccount.balance + amount))) accounts.put(from, (fromAccount.copy(balance = fromAccount.balance - amount))) } }}

Page 16: Pellucid stm

EXTENDED EXAMPLE: SYNCHRONIZED3

import java.util.concurrent._private val accounts = ConcurrentHashMap[Int, Account]()accounts.put(1, Account(1, 100))accounts.put(2, Account(2, 100))

def transfer(to: Int, from: Int, amount: Int){ val toAccount = accounts.get(to) val fromAccount = accounts.get(from) val (firstLock, secondLock) = if(to > from) (toAccount, fromAccount) else (fromAccount, toAccount) firstLock.synchronized{ secondLock.synchronized{ accounts.put(to, (toAccount.copy(balance = toAccount.balance + amount))) accounts.put(from, (fromAccount.copy(balance = fromAccount.balance - amount))) } }}

Page 17: Pellucid stm

Questions?