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