Pellucid stm
-
Upload
dustin-whitney -
Category
Technology
-
view
1.168 -
download
1
description
Transcript of Pellucid stm
SOFTWARE TRANSACTIONAL MEMORY@DUSTINWHITNEY
Alternative to lock-based synchronization
Analogous to database transactions
ACI (ACID with out the ‘D’)
Simple! (well… simplier)
WHAT IS 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?
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)}
CONSISTENT
val protectedInt = Ref(0)
atomic{ transaction => val currentValue = protectedInt.get(transaction) protectedInt.set(currentValue + 1)(transaction)}
val protectedInt = Ref(0)
atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}
ISOLATED
STM is not Durable
DURABLE
ADVANTAGES: DEADLOCK / LIVELOCK
val protectedInt = Ref(0)
atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}
ADVANTAGES: PRIORITY INVERSION
val protectedInt = Ref(0)
atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}
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) }
}
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))}
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")}
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))) ) } }
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))) }}
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))) } }}
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))) } }}
Questions?