13
J Supercomput (2011) 57:203–215 DOI 10.1007/s11227-010-0388-0 Software transactional memories: an approach for multicore programming Damien Imbs · Michel Raynal Published online: 9 February 2010 © Springer Science+Business Media, LLC 2010 Abstract The recent advance of multicore architectures and the deployment of mul- tiprocessors as the mainstream computing platforms have given rise to a new con- current programming impetus. Software transactional memories (STM) are one of the most promising approaches to take up this challenge. The aim of a STM system is to discharge the application programmer from the management of synchronization when he/she has to write multiprocess programs. His/her task is to decompose his/her program into a set of sequential tasks that access shared objects, and to decompose each task in atomic units of computation. The management of the required synchro- nization is ensured by the associated STM system. This paper presents two existing STM systems, and a new one based on time-window mechanism. The paper, which focuses mainly on STM principles, has an introductory and survey flavor. Keywords Concurrent programming · Opacity · Shared object · Software transactional memory · Transaction 1 Introduction The challenging advent of multicore architectures The speed of light has a limit. When combined with other physical and architectural demands, this physical con- straint places limits on processor clocks: their speed is no longer rising. Hence, soft- ware performance can no longer be obtained by increasing CPU clock frequencies. To face this new challenge, manufacturers are investigating and producing what they D. Imbs · M. Raynal ( ) IRISA, Campus de Beaulieu, 35042 Rennes Cedex, France e-mail: [email protected] D. Imbs e-mail: [email protected]

Software transactional memories: an approach for multicore programming

Embed Size (px)

Citation preview

Page 1: Software transactional memories: an approach for multicore programming

J Supercomput (2011) 57:203–215DOI 10.1007/s11227-010-0388-0

Software transactional memories:an approach for multicore programming

Damien Imbs · Michel Raynal

Published online: 9 February 2010© Springer Science+Business Media, LLC 2010

Abstract The recent advance of multicore architectures and the deployment of mul-tiprocessors as the mainstream computing platforms have given rise to a new con-current programming impetus. Software transactional memories (STM) are one ofthe most promising approaches to take up this challenge. The aim of a STM systemis to discharge the application programmer from the management of synchronizationwhen he/she has to write multiprocess programs. His/her task is to decompose his/herprogram into a set of sequential tasks that access shared objects, and to decomposeeach task in atomic units of computation. The management of the required synchro-nization is ensured by the associated STM system. This paper presents two existingSTM systems, and a new one based on time-window mechanism. The paper, whichfocuses mainly on STM principles, has an introductory and survey flavor.

Keywords Concurrent programming · Opacity · Shared object · Softwaretransactional memory · Transaction

1 Introduction

The challenging advent of multicore architectures The speed of light has a limit.When combined with other physical and architectural demands, this physical con-straint places limits on processor clocks: their speed is no longer rising. Hence, soft-ware performance can no longer be obtained by increasing CPU clock frequencies.To face this new challenge, manufacturers are investigating and producing what they

D. Imbs · M. Raynal (�)IRISA, Campus de Beaulieu, 35042 Rennes Cedex, Francee-mail: [email protected]

D. Imbse-mail: [email protected]

Page 2: Software transactional memories: an approach for multicore programming

204 D. Imbs, M. Raynal

call multicore architectures, i.e., architectures in which each chip is made up of sev-eral processors that share a common memory. This constitutes what is called “themulticore revolution” [6].

The main challenge associated with multicore architectures is “how to exploit theirpower?” Of course, the old (classical) “multiprocess programming” (multi-threading)methods are an answer to this question. Basically, these methods provide the pro-grammers with the concept of a lock. According to the abstraction level considered,this lock can be a semaphore object, a monitor object, or the programmer’s favoritesynchronization object.

Unfortunately, traditional lock-based solutions have inherent drawbacks. On theone hand, if the set of data whose accesses are controlled by a single lock is toolarge (large grain), the parallelism can be drastically reduced. On the other hand,the solutions where a lock is associated with each datum (fine grain) are error-prone(possible presence of subtle deadlocks), difficult to design, master and prove correct.In other words, providing the application programmers with locks is far from beingthe panacea when one has to produce correct and efficient multiprocess (multi-thread)programs. Interestingly enough, multicore architectures have (in some sense) rang therevival of concurrent programming.

The Software Transactional Memory approach The concept of Software Transac-tional Memory (STM) is an answer to the previous challenge. The notion of trans-actional memory has first been proposed (fifteen years ago) by Herlihy and Moss toimplement concurrent data structures [7]. It has then been implemented in softwareby Shavit and Touitou [14], and has recently gained a great momentum as a promisingalternative to locks in concurrent programming [3, 5, 11, 13].

Transactional memory abstracts the complexity associated with concurrent ac-cesses to shared data by replacing locking with atomic execution units. In that way,the programmer has to focus where atomicity is required and not on the way it has tobe realized. The aim of an STM system is consequently to discharge the programmerfrom the direct management of synchronization entailed by accesses to concurrentobjects.

More generally, STM is a middleware approach that provides the programmerswith the transaction concept (this concept is close but different from the notion oftransactions encountered in databases [3]). More precisely, a process is designed as(or decomposed into) a sequence of transactions, each transaction being a piece ofcode that, while accessing any number of shared objects, always appears as beingexecuted atomically. The job of the programmer is only to define the units of com-putation that are the transactions. He does not have to worry about the fact that thebase objects can be concurrently accessed by transactions. Except when he definesthe beginning and the end of a transaction, the programmer is not concerned by syn-chronization. It is the job of the underlying STM system to ensure that transactionsexecute as if they were atomic.

Of course, a solution in which a single transaction executes at a time triviallyimplements transaction atomicity but is irrelevant from an efficiency point of view.So, an STM system has to do “its best” to execute as many transactions per time unitas possible. Similarly to a scheduler, an STM system is an on-line algorithm that does

Page 3: Software transactional memories: an approach for multicore programming

Software transactional memories: an approach for multicore 205

not know the future. If the STM is not trivial (i.e., it allows several transactions thataccess the same objects in a conflicting manner to run concurrently), this intrinsiclimitation can direct it to abort some transactions in order to ensure both transactionatomicity and object consistency. From a programming point of view, an abortedtransaction has no effect (it is up to the process that issued an aborted transactionto re-issue it or not; usually, a transaction that is restarted is considered as a newtransaction).

Content of the paper This paper is an introduction to STM systems, with an algo-rithmic flavor. Made up of five main sections, it surveys two existing STM systemsand presents a new one.

More explicitly, first, Sect. 2 presents a consistency condition suited to STM sys-tems (called opacity [4]), and an STM architecture. Then, each of the two follow-ing sections presents existing STM systems that—each in its own way—ensure theopacity consistency condition. The first one (Sect. 3) is a simplified version of thewell-known TL2 system [2] that has proved to be particularly efficient on meaningfulbenchmarks, while the second one (Sect. 4), called JVSTM [1], is based on object ver-sioning. The paper then presents a new STM system based on a logical time window(Sect. 5). In order to allow for easier understanding and comparison, the presentationof all the algorithms is based on a single framework. Finally, Sect. 6 concludes thepaper.

2 An STM computation model

2.1 On STM consistency conditions

The classical consistency criterion for database transactions is serializability [12](sometimes strengthened into “strict serializability,” as implemented when using the2-phase locking mechanism). The serializability consistency criterion involves onlythe transactions that are committed. Said differently, a transaction that aborts is notprevented from accessing an inconsistent state before aborting. In an STM system,the code encapsulated in a transaction can be any piece of code (involving shareddata), and it is not restricted to predefined patterns. Consequently, a transaction al-ways has to operate on a consistent state. To be more explicit, let us consider anexample where a transaction contains the statement x ← a/(b − c) (where a, b and c

are integer data), and let us assume that b − c is different from 0 in all the consistentstates. If the values of b and c read by a transaction come from different states, it ispossible that the transaction obtains values such as b = c (and b = c defines an incon-sistent state). If this occurs, the transaction raises an exception that has to be handledby the process that invoked the corresponding transaction.1 Such bad behaviors haveto be prevented in STM systems: whatever its fate (commit or abort), a transaction

1Even worse undesirable behaviors can be obtained when reading values from inconsistent states. Thisoccurs for example when an inconsistent state provides a transaction with values that generate infiniteloops.

Page 4: Software transactional memories: an approach for multicore programming

206 D. Imbs, M. Raynal

has to always see a consistent state of the data it accesses. The aborted transactionshave to be harmless.

This is what is captured by the opacity consistency condition. Informally sug-gested in [2], and then formally introduced and deeply investigated in [4], opacityrequires that no transaction reads values from an inconsistent global state. It is strictserializability when considering each committed transaction entirely, and an appro-priate read prefix of each aborted transaction.

More precisely, let us associate with each aborted transaction T the read prefix thatcontains all its read operations until T aborts (if the abort is entailed by a read, thisread is not included in the prefix). An execution of a set of transactions satisfies theopacity condition if all the committed transactions and the read prefix of each abortedtransaction appear as if they have been executed one after the other, this sequentialorder being in agreement with their real time occurrence order. A formal definitionof opacity appears in [4]. A very general framework for consistency conditions isintroduced in [9], where the virtual world consistency condition is also introduced.A protocol implementing this general condition is described in [9].

2.2 The STM system interface

An STM system provides each transaction T with four operations denoted beginT (),X.readT (), X.writeT (), and try_to_commitT (), where X is a shared base object.

– beginT () is invoked by T when it starts. It initializes local control variables.– X.readT () is invoked by T to read the base object X. That operation returns a value

of X or the control value abort . If abort is returned, the invoking transaction isaborted (in that case, the corresponding read does not belong to the read prefixassociated with T ).

– X.writeT (v) is invoked by T to update X to the new value v. That operation returnsthe control value ok or the control value abort . Like in the operation X.readT (),if abort is returned, the invoking transaction is aborted.

– If a transaction attains its last statement (as defined by the user, which means it hasnot been aborted before), it executes the operation try_to_commitT (). That opera-tion decides the fate of T by returning commit or abort . (Let us notice, a transac-tion T that invokes try_to_commitT () has not been aborted during an invocation ofX.readT ().)

2.3 The incremental read/deferred update model

In this transaction system model, each transaction T uses a local working space.When T invokes X.readT () for the first time, it reads the value of X from the sharedmemory and copies it into its local working space. Later X.readT () invocations (ifany) use this copy. So, if T reads X and then Y , these reads are done incrementally,and the state of the shared memory can have changed in between.

When T invokes X.writeT (v), it writes v into its working space (and doesnot access the shared memory). Finally, if T is not aborted while it is executingtry_to_commitT (), it copies the values written (if any) from its local working spaceto the shared memory. (A similar deferred update model is used in some databasetransaction systems.)

Page 5: Software transactional memories: an approach for multicore programming

Software transactional memories: an approach for multicore 207

3 A sketch of TL2 (transactional locking 2)

3.1 Aim and principles

The TL2 STM system, introduced by Dice, Shalev and Shavit [2], aims at reducingthe synchronization cost due to the read, write and validation (i.e., try_to_commit())operations. To that end, it associates a lock with each data object and uses a logicalglobal clock (integer) that is read by all the transactions and increased by each writingtransaction that commits. This global clock is basically used to validate the consis-tency of the state of the data objects a transaction is working on. The TL2 protocolis particularly efficient when there are few conflicts between concurrent transactions.(Two transactions conflict if they concurrently access the same object and one accessis a write.)

TL2 ensures the opacity property. The performance study depicted in [2] (basedon a red-black tree benchmark) shows that TL2 is pretty efficient. It has neverthelessscenarios in which a transaction is directed to abort despite the fact that it has readvalues from a consistent state. (These scenarios depend on the value of the globalclock. They can occur when, despite the fact that all the values read by a transactionT are mutually consistent, one of them has been written by a transaction concurrentwith T .)

3.2 A simplified version of TL2

A very schematic description of the operations beginT (), X.readT (), X.writeT (v) andtry_to_commitT () used in TL2 [2] is given in Fig. 1 for an update transaction and inFig. 2 for a read-only transaction. As indicated previously, the protocols implement-ing these operations are based on a global (logical) clock plus one lock per object.

The global clock, denoted CLOCK, is increased (atomic Fetch&Increment() oper-ation) each time an update transaction T invokes try_to_commitT () (line 11). More-over, when a transaction starts it invokes the additional operation beginT () to obtaina birth-date (defined as the current value of the clock).

At the implementation level, an object X is made up of two fields: a data fieldX.value containing the current value of the object, and a control field X.date con-taining the date at which that value was created (line 12 of try_to_commitT ()). A lockis associated with each object.

The case of an update transaction Each transaction T manages a local read set lrsT ,and a local write set lwsT . As far as a X.readT () is concerned, we have the following.If, previously, a local copy lcx of the object X has been created by an invocation ofX.writeT (v) issued by the same transaction, its value is returned (lines 01–02). Other-wise, X is read from the shared memory, and X’s id is added to the local read set lrsT(line 03). Finally, if the date associated with the current value of X is greater than thebirth-date of T , the transaction is aborted (line 04). (This is because T has possiblyread other values that are no longer consistent with the value of X just obtained.) Ifthe date associated with the current value of X is not greater than the birth-date ofT , that value is returned by the X.readT () operation. (In that case, the value read isconsistent with the values previously read by T .)

Page 6: Software transactional memories: an approach for multicore programming

208 D. Imbs, M. Raynal

operation beginT (): birthdate ← CLOCK.==================================================================operation X.readT ():(01) if (there is a local copy lcx of X)(02) then return (lcx.value) % the local copy lcx was created by a write of X %(03) else lcx ← copy of X read from the shared memory; lrsT ← lrsT ∪ {X};(04) if lcx.date > birthdate then return (abort) else return (lcx.value) end if(05) end if.==================================================================operation X.writeT (v):(06) if (there is no local copy of X) then allocate local space lcx for a copy end if;(07) lcx.value ← v; lwsT ← lwsT ∪ {X};(08) return (ok).==================================================================operation try_to_commitT ():(09) lock all the objects in (lrsT ∪ lwsT );(10) for each X ∈ lrsT do % the date of X is read from the shared memory %(11) if X.date > birthdate then release all the locks; return (abort) end if end for;(12) commit_date ← Fetch&Increment(CLOCK);(13) for each X ∈ lwsT do X ← (lcx.value, commit_date) end for;(14) release all the locks; return (commit).

Fig. 1 TL2 algorithm for an update transaction

operation beginT (): birthdate ← CLOCK.===========================================================operation X.readT ():(01) lcx ← copy of X read from the shared memory;(02) if lcx.date > birthdate then return (abort) else return (lcx.value) end if.===========================================================operation try_to_commitT (): return(commit).

Fig. 2 TL2 algorithm for a read-only transaction

The operation X.writeT (v) in TL2 and the one in the proposed protocol are similar.If there is no local copy of X, one is created and its value field is set to v. The localwrite set, lwsT is also updated to remember that X has been written by T . The lifetimeof the local copy lcx of X created by a X.writeT (v) operation spans the duration ofthe transaction T .

When a transaction T invokes try_to_commitT (), it first locks all the objects inlrsT ∪ lwsT . Then, T checks if the current values of the objects X it has read arestill mutually consistent, and consistent with respect to the new values it has (locally)written. This is done by comparing the current date X.date of each object X that hasbeen read to the birth-date of T . If one of these dates is greater than its birth-date,there is a possible inconsistency and consequently T is aborted (line 11). Otherwise,T can be committed. Before being committed (line 14), T has to set the objects it haswritten to their new values (line 13). Their control part has also to be updated: theyare set to the last clock value obtained by T (line 12). Finally, T releases the locksand commits.

Page 7: Software transactional memories: an approach for multicore programming

Software transactional memories: an approach for multicore 209

Remark This presentation of the try_to_commitT () operation of TL2 does not takeinto account all of its aspects. As an example, if on line 09, all the locks cannot beimmediately obtained, TL2 can abort the transaction (and restart it later). This canallow for more efficient behaviors. Moreover, the lock of an object is used to containits date value (this allowing for more efficient read operations).

The Case of a read-only transaction If a transaction T does not modify the sharedobjects, the code of its X.readT () and try_to_commitT () operations simplify as shownin Fig. 2.

Each time a read-only transaction T reads an object X, it obtains its value from theshared memory. Then, if the date associated with the value it has read is not greaterthan its birth-date, the read is valid and the value is returned. Otherwise, T is aborted.Let us notice that a read-only transaction does not manage a local read set.

Finally, the operation try_to_commitT () always returns commit . This is because,if a read-only transaction T has never been aborted when it read base objects, we canconclude that T has read object values that are mutually consistent.

4 A Sketch of the JVSTM system

4.1 Aim and principles

This system, introduced by Cachopo and Rito-Silva [1], is based on object multi-versioning. It uses a logical clock to timestamp the transactions and allow them toread an appropriate version of an object.

The validation phase of the transactions (i.e., the part corresponding to thetry_to_commit() operation) is executed in mutual exclusion: they are encapsulatedwith the “synchronized” construct provided by JAVA, the implementation ofwhich is lock-based. Interestingly (due to the multiplicity of versions), the read-onlytransactions are never aborted.

Each object is implemented by a list of versions. JVSTM provides a garbage col-lector mechanism that discards the versions older than the oldest transaction still inthe system.

4.2 A Simplified version of JVSTM

A very schematic description of the X.readT (), X.writeT (v) and try_to_commitT ()

operations used in JVSTM [1] is given in Fig. 3 for an update transaction and inFig. 4 for a read-only transaction (as for TL2, a transaction that starts as a read-onlytransaction and finally issues a write can be aborted). These protocols are very in-formally described in [1]. These informal descriptions include a lot of improvementsthat are not considered here.

As indicated previously, the protocols implementing these operations are basedon a global (logical) clock and a global lock. The global clock, denoted CLOCK, isincreased when an update transaction T invokes try_to_commitT () (lines 13 and 15).Since, due to the use of a global lock, the try_to_commit() operations are executed

Page 8: Software transactional memories: an approach for multicore programming

210 D. Imbs, M. Raynal

operation X.beginT (): birthdate ← CLOCK============================================================================operation X.readT ():(01) if (there is a local copy lx of X)(02) then return (lx.value)

(03) else lrsT ← lrsT ∪ {X};(04) x ← X; % pointer on the list of versions of the object %(05) while ((↓ x).date > birthdate) do x ← (↓ x).next end while;(06) return ((↓ x).value)(07) end if============================================================================operation X.writeT (v):(08) if (there is no local copy of X) then allocate space lx for a copy end if;(09) lx.value ← v;(10) lwsT ← lwsT ∪ {X}============================================================================operation try_to_commitT ():(11) acquire the lock; % commits are mutually exclusive %(12) for each X ∈ lrsT do if (↓ X).date > birthdate then release lock; return (abort) end if end for;(13) commit_date ← CLOCK + 1;(14) for each lx ∈ lwsT do lx.next ← X; lx.date ← commit_date; X ← (↑ lx) end for;(15) CLOCK ← commit_date;(16) release the lock;(17) return (commit)

Fig. 3 JVSTM algorithm for an update transactions

in mutual exclusion, there are no concurrent updates of CLOCK. Moreover, (as inTL2) when a transaction starts, it invokes the additional operation beginT () to obtaina birth-date (defined as the current value of the clock).

At the implementation level, an object X is a pointer on a list of records madeup of three fields: a data field X.value containing the current value of the object, acontrol field X.date containing the date at which that value was created (see line 15of try_to_commitT ()) and a pointer on the next structure in the list.

If Y is a variable containing a pointer, (↓ Y) denotes the variable pointed by Y . IfX is a variable, (↑ X) denotes a pointer on X.

The case of an update transaction Each transaction T manages two sets (as in theproposed protocol): a local read set lrsT , and a local write set lwsT .

As far as a X.readT () operation is concerned we have the following. If, previously,a local copy lx of the object X has been created by an invocation of X.writeT (v)

issued by the same transaction, its value is returned (lines 01–02). Otherwise, X’s idis added to the local read set lrsT (line 04) and the most recent value, at least as oldas the transaction’s birth-date, is fetched from the list of versions of X (lines 05–06)(so the set of values read is consistent). Let us note that, due to the multiplicity ofversions, a X.readT () operation never forces a transaction to abort.

The operation X.writeT (v) in JVSTM and the one in the proposed protocol aresimilar. If there is no local copy of X, one is created and its value field is set to v. Thelocal write set lwsT is updated accordingly. As in the previous protocols, the lifetimeof the local copy lx of X created by a X.writeT (v) operation spans the duration of T .

Page 9: Software transactional memories: an approach for multicore programming

Software transactional memories: an approach for multicore 211

operation X.initT (): birthdate ← Clock================================================operation X.readT ():(01) x ← X;(02) while ((↓ x).date > birthdate) do x ← (↓ x).next end while;(03) return ((↓ x).value);================================================operation try_to_commitT (): return (commit)

Fig. 4 JVSTM algorithm for a read-only transactions

When a transaction T invokes try_to_commitT (), it first acquires the global lock(line 11). Then, T checks if the current values of the objects X has read are the mostrecent, and consistent with respect to the new values it has (locally) written. This isdone by comparing the current date X.date of each object X that has been read to thebirth-date of T (line 12). If one of these dates is greater than its birth-date, there is apossible inconsistency and consequently T is aborted (line 12). Otherwise, T can becommitted. Before being committed, T has to insert the new versions of the objectsit has written into their lists of versions (line 14). Their control part has also to beupdated: they are set to the current clock value obtained by T (incremented by oneas shown on line 13). Finally, T increments the clock, releases the global lock andcommits (lines 15–17).

Remark This presentation of the try_to_commitT () operation of JVSTM does nottake into account all of its aspects. Among those, there is a mechanism that keepstrack of the birth-dates of the transactions that are not yet committed. A transactionthat commits then discards all the versions of the objects it writes that are no longeraccessible (that is, that will never be read by any live transaction because they are tooold). The JAVA garbage collector then frees the corresponding memory locations.

The case of a read-only transaction If a transaction T does not modify the sharedobjects, the code of its X.readT () and try_to_commitT () operations can be simplifiedas shown in Fig. 4.

Each time a read-only transaction T reads an object X, it obtains (from the sharedmemory) the most recent value at least as old as the transaction’s birth-date. A read-only transaction does not manage a local read set.

Finally, the operation try_to_commitT () always returns commit . This is because aread-only transaction can never abort. This is due to the presence of multiple versionswhich always allow a read-only transaction T to obtain mutually consistent versionsof all the objects it has read.

5 A window-based STM system

This STM system has been proposed in [8] where the notion of obligation propertyis introduced. It is called window-based because a logical time window is associatedwith each transaction, and a transaction has to be aborted when its window becomesempty. The opacity property does not prevent an STM system from aborting all the

Page 10: Software transactional memories: an approach for multicore programming

212 D. Imbs, M. Raynal

transactions. An obligation property states circumstances in which an STM systemmust commit a transaction T . Two obligation properties are defined in [8], and theaim of the system described in [8] is to satisfy both opacity and these obligationproperties.

5.1 The STM control variables

The object fields, the object locks, the logical global clock, the local sets lrsT andlwsT have the same meaning as in TL2. The following additional (shared or local)control variables are also used:

– A set RSX per base object X. This set, initialized to ∅, contains the identities of thetransactions that have read X since the last update of X. A transaction adds its idto RSX to indicate a possible read/write conflict.

– A control variable MAX_DATET , initialized to +∞, is associated with each trans-action T . It keeps the smallest date at which an object read by T has been overwrit-ten. That variable allows the transaction T to safely evaluate the abstract propertyP 2(T ). As we will see, we have P 2(T ) ⇒ (MAX_DATET = +∞), and the STMsystem will direct T to commit when MAX_DATET = +∞.

– read_onlyT is a local boolean, initialized to true, that is set to false, if T invokes aX.writeT (v) operation.

– min_dateT is a local variable containing the greatest date of the objects T hasread so far. Its initial value is 0. Combined with MAX_DATET , that variable al-lows a safe evaluation of the abstract property P 1(T ). As we will see, we haveP 1(T ) ⇒ (min_dateT ≤ MAX_DATET), and the STM system will not abort aread-only transaction T if min_dateT ≤ MAX_DATET .

5.2 The STM operations

The three operations that constitute the STM system, X.readT (), X.writeT (v), andtry_to_commitT (), are described in Fig. 5. As in a lot of other protocols (e.g., STM ordiscrete event simulation), the underlying idea is to associate a time window, namely[min_dateT ,MAX_DATET ], with each transaction T . This time window is managedas follows:

– When a read-only or update transaction T reads a new object (from the sharedmemory), it accordingly updates min_dateT , and aborts if its time window becomesempty. A time window becomes empty when the system is unable to guaranteethat the values previously read by T and the value it has just obtained belong to aconsistent snapshot.

– When an update transaction T is about to commit, it has two things to do. First,write into the shared memory the new values of the objects it has updated, anddefine their dates as the current clock value. These writes may render inconsistentthe snapshot of a transaction T ′ that has already obtained values and will read anew object in the future. Hence, in order to prevent such an inconsistency from oc-curring (see the previous item), the transaction T sets MAX_DATET ′ to the currentclock value if ((T ′ ∈ RSX) ∧ (X ∈ lwsT)) and (MAX_DATET ′ = +∞).

Page 11: Software transactional memories: an approach for multicore programming

Software transactional memories: an approach for multicore 213

operation X.readT ():(01) if (there is no local copy of X) then(02) allocate local space lcx for a copy;(03) lock X; lcx ← X; RSX ← RSX ∪ {T }; unlock X;(04) lrsT ← lrsT ∪ {X}; min_dateT ← max(min_dateT , lcx.date);(05) if (min_dateT > MAX_DAT ET ) then return(abort) end if(06) end if;(07) return (lcx.value).================================================================operation X.writeT (v):(08) read_onlyT ← false;(09) if (there is no local copy of X) then allocate local space lcx for a copy end if;(10) lcx.value ← v; lwsT ← lwsT ∪ {X};(11) return (ok).================================================================operation try_to_commitT ():(12) if (read_onlyT )

(13) then return(commit)

(14) else lock all the objects in lrsT ∪ lwsT ;(15) if (MAX_DATET = +∞) then release all the locks; return(abort) end if;(16) current_time ← CLOCK;(17) for each T ′ ∈ ( ∪X∈lwsT RSX

)

do C&S(MAX_DATET ′ ,+∞, current_time) end for;(18) commit_time ← Increment&Fetch(CLOCK);(19) for each X ∈ lwsT do X ← (lcx.value, commit_time); RSX ← ∅ end for;(20) release all the locks; return(commit)

(21) end if.

Fig. 5 A window-based STM system

The operation X.readT () When T invokes X.readT (), it obtains the value of X

currently kept in the local memory if there is one (lines 01 and 07). Otherwise, T firstallocates space in its local memory for a copy of X (line 02), obtains the value of X

from the shared memory and updates RSX accordingly (line 03). The update of RSX

allows T to announce a read/write conflict that will occur with the transactions thatwill update X. This line is the only place where read/write conflicts are announced inthe proposed STM algorithm.

Then, T updates its local control variables lrsT and min_dateT (line 04) in orderto keep them consistent. Finally, T checks its time window (line 05) to know if itssnapshot is consistent. If the time window is empty, the value it has just obtained fromthe memory can make its current snapshot inconsistent and consequently T aborts.

Remark Looking into the details, when a transaction T reads X from the sharedmemory, a single cause can entail the window predicate (min_dateT > MAX_DATET )

to become true: min_dateT has just been increased, and MAX_DATET has been de-creased to a finite value. T is then aborted due to a write/read conflict on X and aread/write conflict on Y = X.

The operation X.writeT () The text of the algorithm implementing X.writeT () isvery simple. The transaction first sets a flag to record that it is not a read-only trans-action (line 08). If there is no local copy of X, corresponding space is allocated in the

Page 12: Software transactional memories: an approach for multicore programming

214 D. Imbs, M. Raynal

local memory (line 09); let us remark that this does not entail a read of X from theshared memory. Finally, T updates the local copy of X, and records in lrwT that ithas locally written the copy of X (line 10). It is important to notice that an invocationof X.writeT () is purely local: it involves no access to the shared memory, and cannotentail an immediate abort of the corresponding transaction.

The operation try_to_commitT () This operation works as follows. If the invokingtransaction is a read-only transaction, it is committed (lines 12–13). So, a read-onlytransaction can abort only during the invocation of a X.readT () operation (line 05).

If the transaction T is an update transaction, try_to_commitT () first locks all theobjects accessed by T (line 14). (In order to prevent deadlocks, it is assumed thatthese objects are locked according to a predefined total order, e.g., their identity or-der.) Then, T checks if MAX_DATET = +∞. If this is the case, there is a read/writeconflict: T has read an object that since then has been overwritten. Consequently,there is no guarantee for the current snapshot of T (that is consistent) and the writeoperations of T to appear as being atomic. T consequently aborts (after having re-leased all the locks it has previously acquired, line 15).

If the predicate MAX_DATET = +∞ is true, T will necessarily commit. But, be-fore releasing the locks and committing (line 20), T has to (1) write in the sharedmemory the new values of the objects with their new dates (lines 18–19), and (2) up-date the control variables to indicate possible (read/write with read in the past, orwrite/read with read in the future) conflicts due to the objects it has written. Asindicated at the beginning of this section, (1) read/write conflicts are managed bysetting MAX_DATET ′ to the current clock value for all the transactions T ′ such that((T ′ ∈ RSX)∧(X ∈ lwsT)) (lines 16–17), and consequently RSX is reset to ∅ (line 19),while (2) write/read conflicts on an object X are managed by setting the date of X tothe commit time of T .

As two transactions T 1 and T 2 can simultaneously find MAX_DATET ′ = +∞ andtry to change its value, the modification of MAX_DATET ′ is controlled by an atomiccompare-and-swap operation (denoted C&S(), line 17).

6 Conclusion

The aim of this paper was to show that Software Transactional Memory is a novelpromising approach to address multiprocess programming. It discharges the program-mer from using and managing base synchronization mechanism. The programmerhas to focus his/her attention only (1) on the decomposition of his/her applicationinto processes, and, (2) on its decomposition of each process into atomic units. Toillustrate these notions, several STM protocols have been presented. All are based ona logical global clock, and use locks. The interested reader will find a formal proof ofthe window algorithm in [10].

Acknowledgements We want to thank Professor Victor Malyshkin for his support. We also want tothank Professor Yuri Karpov and his student Alexey Belyaev who found a bug in a previous version of ouralgorithm when they designed a Promela model of our algorithm and checked it with the Spin software.

Page 13: Software transactional memories: an approach for multicore programming

Software transactional memories: an approach for multicore 215

References

1. Cachopo J, Rito-Silva A (2006) Versioned boxes as the basis for transactional memory. Sci ComputProgr 63(2):172–175

2. Dice D, Shalev O, Shavit N (2006) Transactional locking II. In: Proc. 20th int’l symposium on dis-tributed computing (DISC’06). LNCS, vol 4167. Springer, Berlin, pp 194–208

3. Felber P, Fetzer Ch, Guerraoui R, Harris T (2008) Transactions are coming back, but are they thesame? ACM SIGACT News, Distributed Comput Column 39(1):48–58

4. Guerraoui R, Kapałka M (2008) On the correctness of transactional memory. In: Proc. 13th ACMSIGPLAN symposium on principles and practice of parallel programming (PPoPP’08), pp 175–184

5. Harris T, Cristal A, Unsal OS, Ayguade E, Gagliardi F, Smith B, Valero M (2007) Transactionalmemory: an overview. IEEE Micro 27(3):8–29

6. Herlihy MP, Luchangco V (2008) Distributed Computing and the Multicore Revolution. ACMSIGACT News, Distributed Comput Column 39(1):62–72

7. Herlihy MP, Moss JEB (1993) Transactional memory: architectural support for lock-free data struc-tures. In: Proc 20th ACM int’l symposium on computer architecture (ISCA’93), pp 289–300, 1993

8. Imbs D, Raynal M (2009) Provable STM Properties: Leveraging clock and locks to favor commitand early abort. In: Proc 10th int’l conference on distributed computing and networking (ICDCN’09).LNCS, vol 5408. Springer, Berlin, pp 67–78

9. Imbs D, Raynal M (2009) A versatile STM protocol with invisible read operations that satisfies thevirtual world consistency condition. In: 16th Colloquium on structural information and communica-tion complexity (SIROCCO’09). LNCS, vol 5869. Springer, Berlin, pp 276–290

10. Imbs D, Raynal M (2009) Software transactional memories: an approach for multicore programming.In: 10th int’l conference on parallel computing technologies (PaCT’09). LNCS, vol 5698. Springer,Berlin, pp 26–40

11. Larus J, Kozyrakis Ch (2008) Transactional memory: is TM the answer for improving parallel pro-gramming? Commun ACM 51(7):80–89

12. Papadimitriou ChH (1979) The serializability of concurrent updates. J ACM 26(4):631–65313. Raynal M (2008) Synchronization is coming back, but is it the same? Keynote speech. In: IEEE 22nd

int’l conf on advanced inf. networking and applications (AINA’08), pp 1–10, 200814. Shavit N, Touitou D (1997) Software transactional memory. Distrib Comput 10(2):99–116