Data.Atomics.Counter

atomic-primops-0.8.8: A safe approach to CAS and other atomic ops in Haskell.

Safe Haskell | None
Language | Haskell2010

Data.Atomics.Counter

Contents

- Type of counters of counters and tickets
- Creating counters
- Tickets, used for compare-and-swap
- Atomic memory operations
- Non-atomic operations

Description

Integer counters providing thread-safe, lock-free mutation functions.

Atomic counters are represented by a single memory location, such that built-in processor instructions are sufficient to perform fetch-and-add or compare-and-swap.

Remember, contention on such counters should still be minimized!

Synopsis

- data AtomicCounter
- newCounter :: Int -> IO AtomicCounter
- type CTicket = Int
- peekCTicket :: CTicket -> Int
- casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)
- incrCounter :: Int -> AtomicCounter -> IO Int
- incrCounter_ :: Int -> AtomicCounter -> IO ()
- readCounter :: AtomicCounter -> IO Int
- readCounterForCAS :: AtomicCounter -> IO CTicket
- writeCounter :: AtomicCounter -> Int -> IO ()

# Type of counters of counters and tickets

data AtomicCounter #

The type of mutable atomic counters.

# Creating counters

newCounter :: Int -> IO AtomicCounter #

Create a new counter initialized to the given value.

# Tickets, used for compare-and-swap

See the documentation for Data.Atomics for more explanation of the ticket abstraction. The same ideas apply here for counters as for general mutable locations (IORefs).

type CTicket = Int #

You should not depend on this type. It varies between different implementations of atomic counters.

peekCTicket :: CTicket -> Int #

Opaque tickets cannot be constructed, but they can be destructed into values.

# Atomic memory operations

casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket) #

Compare and swap for the counter ADT. Similar behavior to `casIORef`, in particular, in both success and failure cases it returns a ticket that you should use for the next attempt. (That is, in the success case, it actually returns the new value that you provided as input, but in ticket form.)

incrCounter :: Int -> AtomicCounter -> IO Int #

Increment the counter by a given amount. Returns the value AFTER the increment (in contrast with the behavior of the underlying instruction on architectures like x86.)

Note that UNLIKE with boxed implementations of counters, where increment is based on CAS, this increment is O(1). Fetch-and-add does not require a retry loop like CAS.

incrCounter_ :: Int -> AtomicCounter -> IO () #

An alternate version for when you don't care about the old value.

# Non-atomic operations

readCounter :: AtomicCounter -> IO Int #

Equivalent to `readCounterForCAS` followed by `peekCTicket`.

readCounterForCAS :: AtomicCounter -> IO CTicket #

Just like the Data.Atomics CAS interface, this routine returns an opaque ticket that can be used in CAS operations. Except for the difference in return type, the semantics of this are the same as `readCounter`.

writeCounter :: AtomicCounter -> Int -> IO () #

Make a non-atomic write to the counter. No memory-barrier.