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  * Threads provide a way to run multiple parts of the code in parallel. When you
30  * launch a new thread, the execution is split and both the new thread and the
31  * caller run in parallel.
32  *
33  * To use a $(U Thread), you construct it directly with the function to execute
34  * as the entry point of the thread. $(U Thread) has multiple template
35  * constructors, which means that you can use several types of entry points:
36  * $(UL
37  * $(LI functions with no arguments)
38  * $(LI delegates with no arguments))
39  *
40  * $(PARA
41  * The thread ends when its function is terminated. If the owner $(U Thread)
42  * instance is destroyed before the thread is finished, the destructor will wait
43  * (see `wait()`).)
44  *
45  * Example:
46  * ---
47  * // example 1: function
48  * void threadFunc()
49  * {
50  *   ...
51  * }
52  *
53  * auto thread = new Thread(&threadFunc);
54  * thread.launch();
55  *
56  * // example 2: delegate
57  * class Task
58  * {
59  *    void run()
60  *    {
61  *       ...
62  *    }
63  * }
64  *
65  * auto task = new Task();
66  * auto thread = new Thread(&task.run);
67  * thread.launch();
68  * ---
69  */
70 module nudsfml.system.thread;
71 
72 import core = core.thread;
73 
74 /**
75  * Utility class to manipulate threads.
76  */
77 class Thread
78 {
79 	private core.Thread m_thread;
80 
81 	/**
82 	 * Construct the thread from a functor with no argument
83 	 *
84 	 * Params:
85 	 * 		fn  = The function to use as the entry point of the thread
86 	 * 		sz  = The size of the stack
87 	 */
88 	this(void function() fn, size_t sz = 0)
89 	{
90 		m_thread = new core.Thread(fn,sz);
91 	}
92 
93 	/**
94 	 * Construct the thread from a delegate with no argument
95 	 *
96 	 * Params:
97 	 * 		dg  = The delegate to use as the entry point of the thread
98 	 * 		sz  = The size of the stack
99 	 */
100 	this(void delegate() dg, size_t sz = 0)
101 	{
102 		m_thread = new core.Thread(dg, sz);
103 	}
104 
105 	/// Destructor
106 	~this()
107 	{
108 		import nudsfml.system.config;
109 		mixin(destructorOutput);
110 	}
111 
112 	/// Run the thread.
113 	void launch()
114 	{
115 		m_thread.start();
116 	}
117 
118 	/// Wait until the thread finishes.
119 	void wait()
120 	{
121 		if(m_thread.isRunning())
122 		{
123 			m_thread.join(true);
124 		}
125 	}
126 }
127 
128 unittest
129 {
130 	version(DSFML_Unittest_System)
131 	{
132 		import std.stdio;
133 		import nudsfml.system.sleep;
134 
135 		void secondThreadHello()
136 		{
137 			for(int i = 0; i < 10; ++i)
138 			{
139 				writeln("Hello from the second thread!");
140 			}
141 		}
142 
143 		writeln("Unit test for Thread class");
144 		writeln();
145 
146 		writeln("Running two functions at once.");
147 
148 		auto secondThread = new Thread(&secondThreadHello);
149 
150 		secondThread.launch();
151 
152 		for(int i = 0; i < 10; ++i)
153 		{
154 			writeln("Hello from the main thread!");
155 		}
156 
157 		sleep(seconds(1));
158 
159 		//writeln("Letting a thread run completely before going back to the main thread.");
160 
161 		//secondThread = new Thread(&secondThreadHello);//To prevent threading errors, create a new thread before calling launch again
162 
163 		//secondThread.launch();
164 
165 		//secondThread.wait();
166 
167 		//for(int i = 0; i < 10; ++i)
168 		//{
169 		//	writeln("Hello from the main thread!");
170 		//}
171 	}
172 }