1 /* 2 * DSFML - The Simple and Fast Multimedia Library for D 3 * 4 * Copyright (c) 2013 - 2018 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 * 6 * This software is provided 'as-is', without any express or implied warranty. 7 * In no event will the authors be held liable for any damages arising from the 8 * use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not claim 15 * that you wrote the original software. If you use this software in a product, 16 * an acknowledgment in the product documentation would be appreciated but is 17 * not required. 18 * 19 * 2. Altered source versions must be plainly marked as such, and must not be 20 * misrepresented as being the original software. 21 * 22 * 3. This notice may not be removed or altered from any source distribution 23 * 24 * 25 * DSFML is based on SFML (Copyright Laurent Gomila) 26 */ 27 28 /** 29 * $(U Mutex) stands for "MUTual EXclusion". A mutex is a synchronization 30 * object, used when multiple threads are involved. 31 * 32 * When you want to protect a part of the code from being accessed 33 * simultaneously by multiple threads, you typically use a mutex. When a thread 34 * is locked by a mutex, any other thread trying to lock it will be blocked 35 * until the mutex is released by the thread that locked it. This way, you can 36 * allow only one thread at a time to access a critical region of your code. 37 * 38 * Example: 39 * --- 40 * // this is a critical resource that needs some protection 41 * Database database; 42 * auto mutex = Mutex(); 43 * 44 * void thread1() 45 * { 46 * // this call will block the thread if the mutex is already locked by thread2 47 * mutex.lock(); 48 * database.write(...); 49 * // if thread2 was waiting, it will now be unblocked 50 * mutex.unlock(); 51 * } 52 * 53 * void thread2() 54 * { 55 * // this call will block the thread if the mutex is already locked by thread1 56 * mutex.lock(); 57 * database.write(...); 58 * mutex.unlock(); // if thread1 was waiting, it will now be unblocked 59 * } 60 * --- 61 * 62 * $(PARA Be very careful with mutexes. A bad usage can lead to bad problems, 63 * like deadlocks (two threads are waiting for each other and the application is 64 * globally stuck). 65 * 66 * To make the usage of mutexes more robust, particularly in environments where 67 * exceptions can be thrown, you should use the helper class $(LOCK_LINK) to 68 * lock/unlock mutexes. 69 * 70 * DSFML mutexes are recursive, which means that you can lock a mutex multiple 71 * times in the same thread without creating a deadlock. In this case, the first 72 * call to `lock()` behaves as usual, and the following ones have no effect. 73 * However, you must call `unlock()` exactly as many times as you called 74 * `lock()`. If you don't, the mutex won't be released. 75 * 76 * Note that the $(U Mutex) class is added for convenience, and is nothing more 77 * than a simnple wrapper around the existing core.sync.mutex.Mutex class.) 78 * 79 * See_Also: 80 * $(LOCK_LINK) 81 */ 82 module dsfml.system.mutex; 83 84 import core = core.sync.mutex; 85 86 /** 87 * Blocks concurrent access to shared resources from multiple threads. 88 */ 89 class Mutex 90 { 91 private core.Mutex m_mutex; 92 93 /// Default Constructor 94 this() 95 { 96 m_mutex = new core.Mutex(); 97 } 98 99 /// Destructor 100 ~this() 101 { 102 import dsfml.system.config; 103 mixin(destructorOutput); 104 } 105 106 /** 107 * Lock the mutex 108 * 109 * If the mutex is already locked in another thread, this call will block 110 * the execution until the mutex is released. 111 */ 112 void lock() 113 { 114 m_mutex.lock(); 115 } 116 117 /// Unlock the mutex 118 void unlock() 119 { 120 m_mutex.unlock(); 121 } 122 } 123 124 unittest 125 { 126 version(DSFML_Unittest_System) 127 { 128 import dsfml.system.thread; 129 import dsfml.system.sleep; 130 import std.stdio; 131 132 auto mutex = new Mutex(); 133 134 void secondThreadHello() 135 { 136 mutex.lock(); 137 for(int i = 0; i < 10; ++i) 138 { 139 writeln("Hello from the second thread!"); 140 } 141 mutex.unlock(); 142 } 143 144 145 writeln("Unit test for Mutex class"); 146 writeln(); 147 148 writeln("Locking a mutex and then unlocking it later."); 149 150 auto secondThread = new Thread(&secondThreadHello); 151 152 secondThread.launch(); 153 154 mutex.lock(); 155 156 for(int i = 0; i < 10; ++i) 157 { 158 writeln("Hello from the main thread!"); 159 } 160 161 mutex.unlock(); 162 sleep(seconds(1));//let's this unit test finish before moving on to the next one. 163 writeln(); 164 } 165 }