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