]> git.sesse.net Git - casparcg/blob - concrt_extras/semaphore.h
(no commit message)
[casparcg] / concrt_extras / semaphore.h
1 //--------------------------------------------------------------------------\r
2 // \r
3 //  Copyright (c) Microsoft Corporation.  All rights reserved. \r
4 // \r
5 //  File: concrt_extras.h\r
6 //\r
7 //  Implementation of ConcRT helpers\r
8 //\r
9 //--------------------------------------------------------------------------\r
10 \r
11 #pragma once\r
12 \r
13 #include <concrt.h>\r
14 #include <concurrent_queue.h>\r
15 \r
16 namespace Concurrency\r
17 {       \r
18         class semaphore\r
19         {\r
20         public:\r
21                 explicit semaphore(LONG capacity)\r
22                           : _semaphore_count(capacity)\r
23                 {\r
24                 }\r
25 \r
26                 // Acquires access to the semaphore.\r
27                 void acquire()\r
28                 {\r
29                         // The capacity of the semaphore is exceeded when the semaphore count \r
30                         // falls below zero. When this happens, add the current context to the \r
31                         // back of the wait queue and block the current context.\r
32                         if (InterlockedDecrement(&_semaphore_count) < 0)\r
33                         {\r
34                                 _waiting_contexts.push(Concurrency::Context::CurrentContext());\r
35                                 Concurrency::Context::Block();\r
36                         }\r
37                 }\r
38 \r
39                 // Releases access to the semaphore.\r
40                 void release()\r
41                 {\r
42                   // If the semaphore count is negative, unblock the first waiting context.\r
43                         if (InterlockedIncrement(&_semaphore_count) <= 0)\r
44                         {\r
45                          // A call to acquire might have decremented the counter, but has not\r
46                          // yet finished adding the context to the queue. \r
47                          // Create a spin loop that waits for the context to become available.\r
48                                 Concurrency:: Context* waiting = NULL;\r
49                                 while(!_waiting_contexts.try_pop(waiting))\r
50                                 {\r
51                                         Concurrency::wait(0);\r
52                                 }\r
53 \r
54                                 // Unblock the context.\r
55                                  waiting->Unblock();\r
56                         }\r
57                 }\r
58 \r
59         private:\r
60                 // The semaphore count.\r
61                 LONG _semaphore_count;\r
62 \r
63                 // A concurrency-safe queue of contexts that must wait to \r
64                 // acquire the semaphore.\r
65                 Concurrency::concurrent_queue<Concurrency::Context*> _waiting_contexts;\r
66            \r
67                 semaphore const &operator =(semaphore const&);  // no assignment operator\r
68                 semaphore(semaphore const &);                   // no copy constructor\r
69         };\r
70 }