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 Lock) is a RAII wrapper for DSFML's Mutex. 30 * 31 * By unlocking it in its destructor, it ensures that the mutex will always be 32 * released when the current scope (most likely a function) ends. This is even 33 * more important when an exception or an early return statement can interrupt 34 * the execution flow of the function. 35 * 36 * For maximum robustness, $(U Lock) should always be used to lock/unlock a 37 * mutex. 38 * 39 * Note that this structure is provided for convenience when porting projects 40 * from SFML to DSFML. The same effect can be achieved with scope guards and 41 * Mutex. 42 * 43 * Example: 44 * --- 45 * auto mutex = Mutex(); 46 * 47 * void function() 48 * { 49 * auto lock = Lock(mutex); // mutex is now locked 50 * 51 * // mutex is unlocked if this function throws 52 * functionThatMayThrowAnException(); 53 * 54 * if (someCondition) 55 * return; // mutex is unlocked 56 * 57 * } // mutex is unlocked 58 * --- 59 * 60 * $(PARA Because the mutex is not explicitly unlocked in the code, it may 61 * remain locked longer than needed. If the region of the code that needs to be 62 * protected by the mutex is not the entire function, a good practice is to 63 * create a smaller, inner scope so that the lock is limited to this part of the 64 * code.) 65 * 66 * Example: 67 * --- 68 * auto mutex = Mutex(); 69 * 70 * void function() 71 * { 72 * { 73 * auto lock = Lock(mutex); 74 * codeThatRequiresProtection(); 75 * 76 * } // mutex is unlocked here 77 * 78 * codeThatDoesntCareAboutTheMutex(); 79 * } 80 * --- 81 * 82 * $(PARA Having a mutex locked longer than required is a bad practice which can 83 * lead to bad performances. Don't forget that when a mutex is locked, other 84 * threads may be waiting doing nothing until it is released.) 85 * 86 * See_Also: 87 * $(MUTEX_LINK) 88 */ 89 module nudsfml.system.lock; 90 91 import nudsfml.system.mutex; 92 93 /** 94 * Automatic wrapper for locking and unlocking mutexes. 95 */ 96 struct Lock 97 { 98 private Mutex m_mutex; 99 100 /** 101 * Construct the lock with a target mutex. 102 * 103 * The mutex passed to Lock is automatically locked. 104 * 105 * Params: 106 * mutex = Mutex to lock 107 */ 108 this(Mutex mutex) 109 { 110 m_mutex = mutex; 111 112 m_mutex.lock(); 113 } 114 115 /// Destructor 116 ~this() 117 { 118 m_mutex.unlock(); 119 } 120 } 121 122 unittest 123 { 124 version(DSFML_Unittest_System) 125 { 126 import nudsfml.system.thread; 127 import nudsfml.system.mutex; 128 import nudsfml.system.sleep; 129 import std.stdio; 130 131 Mutex mutex = new Mutex(); 132 133 void mainThreadHello() 134 { 135 auto lock = Lock(mutex); 136 for(int i = 0; i < 10; ++i) 137 { 138 writeln("Hello from the main thread!"); 139 } 140 //unlock auto happens here 141 } 142 void secondThreadHello() 143 { 144 auto lock = Lock(mutex); 145 for(int i = 0; i < 10; ++i) 146 { 147 writeln("Hello from the second thread!"); 148 } 149 //unlock auto happens here 150 } 151 152 writeln("Unit test for Lock struct"); 153 writeln(); 154 155 writeln("Using a lock in the main and second thread."); 156 157 auto secondThread = new Thread(&secondThreadHello); 158 159 secondThread.launch(); 160 161 mainThreadHello(); 162 163 //let this unit test finish before moving on to the next one 164 sleep(seconds(1)); 165 writeln(); 166 } 167 }