1 /*
2  * Copyright 2015-2017 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SPIRV_CROSS_THREAD_GROUP_HPP
18 #define SPIRV_CROSS_THREAD_GROUP_HPP
19 
20 #include <condition_variable>
21 #include <mutex>
22 #include <thread>
23 
24 namespace spirv_cross
25 {
26 template <typename T, unsigned Size>
27 class ThreadGroup
28 {
29 public:
ThreadGroup(T * impl)30 	ThreadGroup(T *impl)
31 	{
32 		for (unsigned i = 0; i < Size; i++)
33 			workers[i].start(&impl[i]);
34 	}
35 
run()36 	void run()
37 	{
38 		for (auto &worker : workers)
39 			worker.run();
40 	}
41 
wait()42 	void wait()
43 	{
44 		for (auto &worker : workers)
45 			worker.wait();
46 	}
47 
48 private:
49 	struct Thread
50 	{
51 		enum State
52 		{
53 			Idle,
54 			Running,
55 			Dying
56 		};
57 		State state = Idle;
58 
startspirv_cross::ThreadGroup::Thread59 		void start(T *impl)
60 		{
61 			worker = std::thread([impl, this] {
62 				for (;;)
63 				{
64 					{
65 						std::unique_lock<std::mutex> l{ lock };
66 						cond.wait(l, [this] { return state != Idle; });
67 						if (state == Dying)
68 							break;
69 					}
70 
71 					impl->main();
72 
73 					std::lock_guard<std::mutex> l{ lock };
74 					state = Idle;
75 					cond.notify_one();
76 				}
77 			});
78 		}
79 
waitspirv_cross::ThreadGroup::Thread80 		void wait()
81 		{
82 			std::unique_lock<std::mutex> l{ lock };
83 			cond.wait(l, [this] { return state == Idle; });
84 		}
85 
runspirv_cross::ThreadGroup::Thread86 		void run()
87 		{
88 			std::lock_guard<std::mutex> l{ lock };
89 			state = Running;
90 			cond.notify_one();
91 		}
92 
~Threadspirv_cross::ThreadGroup::Thread93 		~Thread()
94 		{
95 			if (worker.joinable())
96 			{
97 				{
98 					std::lock_guard<std::mutex> l{ lock };
99 					state = Dying;
100 					cond.notify_one();
101 				}
102 				worker.join();
103 			}
104 		}
105 		std::thread worker;
106 		std::condition_variable cond;
107 		std::mutex lock;
108 	};
109 	Thread workers[Size];
110 };
111 }
112 
113 #endif
114