1 2 3 4 5 6 7 8 9 10 | cov: proc toTest(x, y: int): int {.noSideEffect.} = case x of 8: if y > 9: 8+1 else: 8+2 of 9: 9 else: 100 # Error: 'toTest' can have side-effects |
1 2 3 4 5 6 7 8 9 | var track = [("line 9", false), ("line 13", false), ...] proc toTest(x, y: int): int {.noSideEffect.} = case x of 8: if y > 9: track[0][1] = true ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var track = [("line 9", false), ("line 13", false), ...] proc setter(x: int) = track[x][1] = true type HideEffects = proc (x: int) {.noSideEffect, raises: [], tags: [].} proc toTest(x, y: int): int = case x of 8: if y > 9: cast[HideEffects](setter)(0) ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import strutils proc readFromFile() {.raises: [].} = # read the first two lines of a text file that should contain numbers # and tries to add them var f: File if open(f, "numbers.txt"): try: var a = readLine(f) var b = readLine(f) echo("sum: " & $(parseInt(a) + parseInt(b))) except OverflowError: echo("overflow!") except ValueError: echo("could not convert string to integer") except IOError: echo("IO error!") except: echo("Unknown exception!") finally: close(f) |
1 2 3 4 5 6 7 8 9 10 | type TagA = object of RootEffect TagB = object of RootEffect proc a() {.tags: [TagA].} = discard proc b() {.tags: [TagB].} = discard proc x(input: int) {.tags: [ ? ].} = if input < 0: a() else: b() |
1 2 3 4 5 6 7 8 9 10 | type TagA = object of RootEffect TagB = object of RootEffect proc a() {.tags: [TagA].} = discard proc b() {.tags: [TagB].} = discard proc x(input: int) {.tags: [TagA, TagB].} = if input < 0: a() else: b() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | proc execProcesses(commands: openArray[string], beforeRunEvent: proc (command: string) = nil): int {.tags: [ExecIOEffect].} ## executes the commands in parallel. The highest return value of ## all processes is returned. Runs `beforeRunEvent` before running each ## command. proc echoCommand(command: string) {.tags: [WriteIOEffect].} = echo command proc compose*() = execProcesses(["gcc -o foo foo.c", "gcc -o bar bar.c", "gcc -o baz baz.c"], echoCommand) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import tables, strutils, threadpool const files = ["data1.txt", "data2.txt", "data3.txt", "data4.txt"] var tab = newCountTable[string]() proc countWords(filename: string) = ## Counts all the words in the file. for word in readFile(filename).split: tab.inc word for f in files: spawn countWords(f) sync() tab.sort() echo tab.largest |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import threadpool, tables, strutils {.pragma isolated, threadvar.} var tab {.isolated.}: CountTable[string] proc rawPut(key: string) = inc(tab, key) proc put(key: string) = pinnedSpawn 0, rawPut(key) proc rawGet(): string = tab.sort() result = tab.largest()[0] proc getMax(): string = let flow = pinnedSpawn(0, rawGet()) result = ^flow proc main = pinnedSpawn 0, (proc () = tab = initCountTable[string]()) for x in split(readFile("readme.txt")): put x echo getMax() main() |
A data race occurs when:
1 2 3 4 5 6 7 8 9 10 11 | var glock: Lock var gdata {.guard: glock.}: int proc invalid = # invalid: unguarded access: echo gdata proc valid = # valid access: {.locks: [glock].}: echo gdata |
1 2 3 4 5 6 7 | template lock(a: Lock; body: untyped) = pthread_mutex_lock(a) {.locks: [a].}: try: body finally: pthread_mutex_unlock(a) |
1 2 3 4 5 6 7 8 9 | var dummyLock {.compileTime.}: int var atomicCounter {.guard: dummyLock.}: int template atomicRead(x): expr = {.locks: [dummyLock].}: memoryReadBarrier() x echo atomicRead(atomicCounter) |
A deadlock occurs when:
Solution?
A deadlock occurs when:
Solution?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | var a, b: Lock[2] var x: Lock[1] # invalid locking order: Lock[1] cannot be acquired before Lock[2]: {.locks: [x].}: {.locks: [a].}: ... # valid locking order: Lock[2] acquired before Lock[1]: {.locks: [a].}: {.locks: [x].}: ... # invalid locking order: Lock[2] acquired before Lock[2]: {.locks: [a].}: {.locks: [b].}: ... # valid locking order, locks of the same level acquired at the same time: {.locks: [a, b].}: ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 | template multilock(a, b: ptr Lock; body: stmt) = if cast[ByteAddress](a) < cast[ByteAddress](b): pthread_mutex_lock(a) pthread_mutex_lock(b) else: pthread_mutex_lock(b) pthread_mutex_lock(a) {.locks: [a, b].}: try: body finally: pthread_mutex_unlock(a) pthread_mutex_unlock(b) |
1 2 3 4 5 6 | proc p() {.locks: 3.} = discard var a: Lock[4] {.locks: [a].}: # p's locklevel (3) is strictly less than a's (4) so the call is allowed: p() |