Wednesday, February 19, 2014

STM - Software Transactional Memory



Table of contents...



What is STM?

STM stands for Software Transactional Memory
  • ScalaSTM is inspired by Clojure STM


  • Configure project

    Using sbt (Scala Build Tool)
    libraryDependencies += ("org.scala-stm" %% "scala-stm" % "0.7")
    Add dependency to pom.xml (for Scala 2.10)
    <dependencies>
      <dependency>
        <groupId>org.scala-stm</groupId>
        <artifactId>scala-stm_2.10</artifactId>
        <version>0.7</version>
      </dependency>
    </dependencies>
    


    Prerequisites

    Required imports
    import scala.concurrent.stm._
    Useful classes and methods
    Ref, atomic, repeat


    A Ref

    A Ref wraps a value and makes it transactional. Once value is wrapped, it's impossible to get or set the value outside of transcation
    val userCount = Ref(42)
    Following attempt to call Ref.set() will not compile
    userCount.get() //will not compile
    Output
    Exception:
    CompilerException: Compiler exception error: line 5: not enough arguments for method get: (implicit txn: scala.concurrent.stm.InTxn)Int. Unspecified value parameter txn. userCount.get() //will not compile ^

    the same with Ref.set() method
    userCount.set() //will not compile
    Output
    Exception:
    CompilerException: Compiler exception error: line 5: not enough arguments for method set: (v: Int)(implicit txn: scala.concurrent.stm.InTxn)Unit. Unspecified value parameter v. userCount.set() //will not compile ^

    Compiler says that both methods have implicit parameter called txn. It represents current transaction. The only way to access value from ref is to call get/set method in transaction


    Atomic - All or nothing

    ScalaSTM allows you to make block of code atomic. That means from the rest of code you cannot see any partial change in this block. atomic block is marked by word "atomic"
    Common template to make block of code atomic
    val result = atomic { implicit tx => /*your code here*/ }
    val x1 = atomic { userCount.get(_) }  //() (result)
    val x2 = atomic { implicit tx => userCount.get }  //() (result)


    Accessing value out of atomic

    Following method will create transaction only for the duration of the call
    userCount.single() //this will work //42 (result)
    and is equivalent to
    atomic { userCount.get(_) }  //42 (result)


    Short forms of Ref.get/Ref.set

    Ref.set
    atomic { implicit tx => userCount.set(56) } //() (result)
    has shorter form
    atomic { implicit tx => userCount() = 56 } //() (result)
    Ref.get
    atomic { implicit tx => val x = userCount.get; x } //42 (result)
    has shorter form
    atomic { implicit tx => val x = userCount(); x } //42 (result)


    Example

    atomic { implicit tx => "Hello world!" }
    Output
    Hello world!

    No comments:

    Post a Comment