or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

concurrency.mdcontrol-flow.mdcore-language.mddata-structures.mddata-utilities.mddev-tools.mdformats.mdindex.mdio.mdjava-interop.mdmath.mdsequences.mdstrings.mdtesting.md

concurrency.mddocs/

0

# Concurrency and State Management

1

2

Safe concurrent programming with atoms, refs, agents, and software transactional memory. Clojure provides several reference types for managing state changes in concurrent programs.

3

4

## Capabilities

5

6

### Atoms

7

8

Atoms provide synchronous, uncoordinated access to a single piece of state.

9

10

```clojure { .api }

11

(atom x & options)

12

;; Creates atomic reference to x

13

;; Options: :meta metadata-map, :validator validator-fn

14

;; Returns: clojure.lang.Atom

15

16

(deref atom)

17

;; Returns current value of atom (same as @atom)

18

;; Returns: Object

19

20

(reset! atom newval)

21

;; Sets atom to newval, returns newval

22

;; Returns: Object

23

24

(swap! atom f & args)

25

;; Atomically swaps value using (f current-value args)

26

;; Retries if value changes during computation

27

;; Returns: new value

28

29

(compare-and-set! atom oldval newval)

30

;; Atomically sets to newval if current equals oldval

31

;; Returns: boolean (true if successful)

32

33

(add-watch atom key fn)

34

;; Adds watch function called on state changes

35

;; fn receives: key, atom, old-state, new-state

36

;; Returns: atom

37

38

(remove-watch atom key)

39

;; Removes watch function for key

40

;; Returns: atom

41

42

(set-validator! atom validator-fn)

43

;; Sets validator function (must return truthy for valid states)

44

;; Returns: atom

45

46

(get-validator atom)

47

;; Returns current validator function

48

;; Returns: function or nil

49

```

50

51

### Refs and Software Transactional Memory

52

53

Refs provide coordinated, synchronous access to shared state using transactions.

54

55

```clojure { .api }

56

(ref x & options)

57

;; Creates transactional reference to x

58

;; Options: :meta metadata-map, :validator validator-fn, :min-history int, :max-history int

59

;; Returns: clojure.lang.Ref

60

61

(dosync & exprs)

62

;; Executes expressions in transaction

63

;; All ref operations must occur within dosync

64

;; Automatically retries on conflicts

65

;; Returns: result of last expression

66

67

(alter ref fun & args)

68

;; Sets ref to (fun current-value args) within transaction

69

;; Must be called within dosync

70

;; Returns: new value

71

72

(commute ref fun & args)

73

;; Like alter but allows more concurrency by commuting at commit time

74

;; Use for commutative operations (order doesn't matter)

75

;; Returns: new value

76

77

(ref-set ref val)

78

;; Sets ref to val within transaction

79

;; Must be called within dosync

80

;; Returns: val

81

82

(ensure ref)

83

;; Protects ref from modification by other transactions

84

;; Must be called within dosync

85

;; Returns: current value

86

87

(ref-history-count ref)

88

;; Returns number of historical values retained

89

;; Returns: int

90

91

(ref-min-history ref)

92

;; Returns minimum history count

93

;; Returns: int

94

95

(ref-max-history ref)

96

;; Returns maximum history count

97

;; Returns: int

98

```

99

100

### Agents

101

102

Agents provide asynchronous, independent state management.

103

104

```clojure { .api }

105

(agent state & options)

106

;; Creates agent with initial state

107

;; Options: :meta metadata-map, :validator validator-fn, :error-handler fn, :error-mode keyword

108

;; Returns: clojure.lang.Agent

109

110

(send agent fn & args)

111

;; Queues fn for execution with agent's state

112

;; Uses thread pool for CPU-bound tasks

113

;; Returns: agent

114

115

(send-off agent fn & args)

116

;; Queues fn for execution with agent's state

117

;; Uses expandable thread pool for I/O-bound tasks

118

;; Returns: agent

119

120

(await & agents)

121

;; Blocks until all queued actions for agents complete

122

;; Returns: nil

123

124

(await-for timeout-ms & agents)

125

;; Like await but with timeout

126

;; Returns: logical true if successful, nil if timeout

127

128

(agent-error agent)

129

;; Returns exception that caused agent to fail, nil if no error

130

;; Returns: Exception or nil

131

132

(clear-agent-errors agent)

133

;; Clears error state and restarts agent

134

;; Returns: agent

135

136

(restart-agent agent new-state & options)

137

;; Clears error and sets new state

138

;; Options: :clear-actions boolean

139

;; Returns: agent

140

141

(set-error-handler! agent handler-fn)

142

;; Sets error handler function

143

;; handler-fn receives: agent, exception

144

;; Returns: agent

145

146

(error-handler agent)

147

;; Returns current error handler

148

;; Returns: function or nil

149

150

(set-error-mode! agent mode)

151

;; Sets error mode: :continue or :fail

152

;; Returns: agent

153

154

(error-mode agent)

155

;; Returns current error mode

156

;; Returns: :continue or :fail

157

158

(shutdown-agents)

159

;; Shuts down agent thread pools

160

;; Call at end of program

161

;; Returns: nil

162

```

163

164

### Vars and Dynamic Binding

165

166

Vars provide thread-local bindings and global state management.

167

168

```clojure { .api }

169

(var symbol)

170

;; Returns var object for symbol (same as #'symbol)

171

;; Returns: clojure.lang.Var

172

173

(binding [bindings*] & body)

174

;; Creates thread-local bindings for dynamic vars

175

;; bindings: [var-symbol value var-symbol value ...]

176

;; Returns: result of last body expression

177

178

(with-local-vars [bindings*] & body)

179

;; Creates thread-local vars

180

;; bindings: [symbol init-value symbol init-value ...]

181

;; Returns: result of last body expression

182

183

(var-get var)

184

;; Returns current value of var

185

;; Returns: Object

186

187

(var-set var val)

188

;; Sets thread-local value of var (must be bound)

189

;; Returns: val

190

191

(alter-var-root var f & args)

192

;; Atomically alters root value using (f current-value args)

193

;; Returns: new value

194

195

(with-redefs [bindings*] & body)

196

;; Temporarily redefines vars during body execution

197

;; bindings: [var-symbol temp-value var-symbol temp-value ...]

198

;; Returns: result of last body expression

199

200

(bound? var)

201

;; Returns true if var has thread-local binding

202

;; Returns: boolean

203

204

(thread-bound? var)

205

;; Returns true if var is bound to separate thread-local value

206

;; Returns: boolean

207

```

208

209

### Delays and Promises

210

211

Utilities for delayed computation and coordination between threads.

212

213

```clojure { .api }

214

(delay & body)

215

;; Creates delay object that computes body on first deref

216

;; Computation happens only once and result is cached

217

;; Returns: clojure.lang.Delay

218

219

(force delay)

220

;; Forces computation of delay (same as deref)

221

;; Returns: result of delay body

222

223

(realized? delay)

224

;; Returns true if delay has been computed

225

;; Returns: boolean

226

227

(promise)

228

;; Creates promise object that can be delivered once

229

;; Returns: clojure.lang.Promise

230

231

(deliver promise val)

232

;; Delivers val to promise

233

;; Can only be called once per promise

234

;; Returns: promise

235

236

(future & body)

237

;; Creates future that computes body in another thread

238

;; Returns: java.util.concurrent.Future

239

240

(future-call f)

241

;; Like future but calls function f with no arguments

242

;; Returns: java.util.concurrent.Future

243

244

(future-cancel future)

245

;; Attempts to cancel future

246

;; Returns: boolean

247

248

(future-cancelled? future)

249

;; Returns true if future was cancelled

250

;; Returns: boolean

251

252

(future-done? future)

253

;; Returns true if future completed

254

;; Returns: boolean

255

```

256

257

**Usage Examples:**

258

259

```clojure

260

;; Atoms for simple state

261

(def counter (atom 0))

262

(swap! counter inc) ; => 1

263

@counter ; => 1

264

(reset! counter 10) ; => 10

265

266

;; Atoms with validation

267

(def positive-num (atom 1 :validator pos?))

268

(swap! positive-num inc) ; => 2

269

; (reset! positive-num -1) ; Would throw exception

270

271

;; Refs for coordinated state

272

(def account1 (ref 100))

273

(def account2 (ref 200))

274

275

(defn transfer [from to amount]

276

(dosync

277

(alter from - amount)

278

(alter to + amount)))

279

280

(transfer account1 account2 50)

281

[@account1 @account2] ; => [50 250]

282

283

;; Agents for async state

284

(def log (agent []))

285

(send log conj "Starting application")

286

(send log conj "Loading config")

287

(await log)

288

@log ; => ["Starting application" "Loading config"]

289

290

;; Dynamic binding

291

(def ^:dynamic *debug* false)

292

293

(defn debug-print [msg]

294

(when *debug*

295

(println "DEBUG:" msg)))

296

297

(binding [*debug* true]

298

(debug-print "This will print"))

299

300

;; Delays and promises

301

(def expensive-calc

302

(delay

303

(Thread/sleep 1000)

304

(* 6 7)))

305

306

@expensive-calc ; Takes 1 second, returns 42

307

@expensive-calc ; Returns 42 immediately

308

309

(def p (promise))

310

(future (deliver p "Hello from future"))

311

@p ; => "Hello from future"

312

313

;; Futures

314

(def f (future

315

(Thread/sleep 1000)

316

(+ 1 2 3)))

317

318

@f ; Blocks until complete, returns 6

319

```