Colobot
resource_owning_thread.h
1 /*
2  * This file is part of the Colobot: Gold Edition source code
3  * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam
4  * http://epsitec.ch; http://colobot.info; http://github.com/colobot
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see http://gnu.org/licenses
18  */
19 
20 #pragma once
21 
22 #include "common/thread/sdl_cond_wrapper.h"
23 #include "common/thread/sdl_mutex_wrapper.h"
24 
25 #include <SDL_thread.h>
26 
27 #include <memory>
28 #include <string>
29 
49 template<typename Resource>
51 {
52 public:
53  using ResourceUPtr = std::unique_ptr<Resource>;
54  using ThreadFunctionPtr = void(*)(ResourceUPtr);
55 
56  CResourceOwningThread(ThreadFunctionPtr threadFunction, ResourceUPtr resource, std::string name = "")
57  : m_threadFunction(threadFunction),
58  m_resource(std::move(resource)),
59  m_name(name)
60  {}
61 
63  {
64  SDL_DetachThread(m_thread);
65  }
66 
67  void Start()
68  {
69  CSDLMutexWrapper mutex;
70  CSDLCondWrapper cond;
71  bool condition = false;
72 
73  ThreadData data;
74  data.resource = std::move(m_resource);
75  data.threadFunction = m_threadFunction;
76  data.mutex = &mutex;
77  data.cond = &cond;
78  data.condition = &condition;
79 
80  SDL_LockMutex(*mutex);
81 
82  m_thread = SDL_CreateThread(Run, !m_name.empty() ? m_name.c_str() : nullptr, reinterpret_cast<void*>(&data));
83 
84  while (!condition)
85  {
86  SDL_CondWait(*cond, *mutex);
87  }
88 
89  SDL_UnlockMutex(*mutex);
90  }
91 
92  void Join()
93  {
94  if (m_thread == nullptr) return;
95  SDL_WaitThread(m_thread, nullptr);
96  m_thread = nullptr;
97  }
98 
99 private:
100  static int Run(void* data)
101  {
102  ThreadFunctionPtr threadFunction = nullptr;
103  ResourceUPtr resource;
104 
105  ThreadData* threadData = reinterpret_cast<ThreadData*>(data);
106  SDL_LockMutex(**threadData->mutex);
107 
108  threadFunction = threadData->threadFunction;
109  resource = std::move(threadData->resource);
110 
111  *threadData->condition = true;
112  SDL_CondSignal(**threadData->cond);
113  SDL_UnlockMutex(**threadData->mutex);
114 
115  threadFunction(std::move(resource));
116  return 0;
117  }
118 
119 private:
120  struct ThreadData
121  {
122  ResourceUPtr resource;
123  CSDLMutexWrapper* mutex = nullptr;
124  CSDLCondWrapper* cond = nullptr;
125  bool* condition = nullptr;
126  ThreadFunctionPtr threadFunction = nullptr;
127  };
128 
129  ThreadFunctionPtr m_threadFunction;
130  ResourceUPtr m_resource;
131  std::string m_name;
132  SDL_Thread* m_thread = nullptr;
133 };
Wrapper around SDL thread allowing passing of resources in safe manner.
Definition: resource_owning_thread.h:50
Wrapper for safe creation/deletion of SDL_cond.
Definition: sdl_cond_wrapper.h:30
Wrapper for safe creation/deletion of SDL_mutex.
Definition: sdl_mutex_wrapper.h:28