]> gitweb.factorcode.org Git - factor.git/blob - basis/concurrency/semaphores/semaphores-docs.factor
factor: trim using lists
[factor.git] / basis / concurrency / semaphores / semaphores-docs.factor
1 IN: concurrency.semaphores
2 USING: help.markup help.syntax quotations calendar ;
3
4 HELP: semaphore
5 { $class-description "The class of counting semaphores. New instances can be created by calling " { $link <semaphore> } "." } ;
6
7 HELP: <semaphore>
8 { $values { "n" "a non-negative integer" } { "semaphore" semaphore } }
9 { $description "Creates a counting semaphore with the specified initial count." } ;
10
11 HELP: acquire-timeout
12 { $values { "semaphore" semaphore } { "timeout" { $maybe duration } } }
13 { $description "If the semaphore has a non-zero count, decrements it and returns immediately. Otherwise, if the timeout is " { $link f } ", waits indefinitely for the semaphore to be released. If the timeout is not " { $link f } ", waits a certain period of time, and if the semaphore still has not been released, throws an error." }
14 { $errors "Throws an error if the timeout expires before the semaphore is released." } ;
15
16 HELP: acquire
17 { $values { "semaphore" semaphore } }
18 { $description "If the semaphore has a non-zero count, decrements it and returns immediately. Otherwise, waits for it to be released." } ;
19
20 HELP: release
21 { $values { "semaphore" semaphore } }
22 { $description "Increments a semaphore's count. If the count was previously zero, any threads waiting on the semaphore are woken up." } ;
23
24 HELP: with-semaphore-timeout
25 { $values { "semaphore" semaphore } { "timeout" { $maybe duration } } { "quot" quotation } }
26 { $description "Calls the quotation with the semaphore held." } ;
27
28 HELP: with-semaphore
29 { $values { "semaphore" semaphore } { "quot" quotation } }
30 { $description "Calls the quotation with the semaphore held." } ;
31
32 ARTICLE: "concurrency.semaphores.examples" "Semaphore examples"
33 "A use-case would be a batch processing server which runs a large number of jobs which perform calculations but then need to fire off expensive external processes or perform heavy network I/O. While for most of the time, the threads can all run in parallel, it might be desired that the expensive operation is not run by more than 10 threads at once, to avoid thrashing swap space or saturating the network. This can be accomplished with a counting semaphore:"
34 { $code
35     "SYMBOL: expensive-section"
36     "requests"
37     "10 <semaphore> '["
38     "    ..."
39     "    _ [ do-expensive-stuff ] with-semaphore"
40     "    ..."
41     "] parallel-map"
42 }
43 "Here is a concrete example which fetches content from 5 different web sites, making no more than 2 requests at a time:"
44 { $code
45     "USING: concurrency.combinators concurrency.semaphores
46 fry http.client kernel urls ;
47
48 {
49     URL\" http://www.apple.com\"
50     URL\" http://www.google.com\"
51     URL\" http://www.ibm.com\"
52     URL\" http://www.hp.com\"
53     URL\" http://www.oracle.com\"
54 }
55 2 <semaphore> '[
56     _ [ http-get nip ] with-semaphore
57 ] parallel-map"
58 } ;
59
60 ARTICLE: "concurrency.semaphores" "Counting semaphores"
61 "Counting semaphores are used to ensure that no more than a fixed number of threads are executing in a critical section at a time; as such, they generalize " { $vocab-link "concurrency.locks" } ", since locks can be thought of as semaphores with an initial count of 1."
62 { $subsections "concurrency.semaphores.examples" }
63 "Creating semaphores:"
64 { $subsections
65     semaphore
66     <semaphore>
67 }
68 "Unlike locks, where acquisition and release are always paired by a combinator, semaphores expose these operations directly and there is no requirement that they be performed in the same thread:"
69 { $subsections
70     acquire
71     acquire-timeout
72     release
73 }
74 "Combinators which pair acquisition and release:"
75 { $subsections
76     with-semaphore
77     with-semaphore-timeout
78 } ;
79
80 ABOUT: "concurrency.semaphores"