| 198 | } |
| 199 | |
| 200 | void Engine::MainLoop(Context & context) |
| 201 | { |
| 202 | while (true) |
| 203 | { |
| 204 | bool hasBroadcast = false; |
| 205 | queue<Message> messages; |
| 206 | |
| 207 | { |
| 208 | unique_lock<mutex> lock(m_mu); |
| 209 | m_cv.wait(lock, [&]() { return m_shutdown || !m_messages.empty() || !context.m_messages.empty(); }); |
| 210 | |
| 211 | if (m_shutdown) |
| 212 | break; |
| 213 | |
| 214 | // As SearchEngine is thread-safe, there is a global order on |
| 215 | // public API requests, and this order is kept by the global |
| 216 | // |m_messages| queue. When a broadcast message arrives, it |
| 217 | // must be executed in any case by all threads, therefore the |
| 218 | // first free thread extracts as many as possible broadcast |
| 219 | // messages from |m_messages| front and replicates them to all |
| 220 | // thread-specific |m_messages| queues. |
| 221 | while (!m_messages.empty() && m_messages.front().m_type == Message::TYPE_BROADCAST) |
| 222 | { |
| 223 | for (auto & b : m_contexts) |
| 224 | b.m_messages.push(m_messages.front()); |
| 225 | m_messages.pop(); |
| 226 | hasBroadcast = true; |
| 227 | } |
| 228 | |
| 229 | // Consumes first non-broadcast message, if any. We process |
| 230 | // only a single task message (in constrast with broadcast |
| 231 | // messages) because task messages are actually search queries, |
| 232 | // whose processing may take an arbitrary amount of time. So |
| 233 | // it's better to process only one message and leave rest to the |
| 234 | // next free search thread. |
| 235 | if (!m_messages.empty()) |
| 236 | { |
| 237 | context.m_messages.push(std::move(m_messages.front())); |
| 238 | m_messages.pop(); |
| 239 | } |
| 240 | |
| 241 | messages.swap(context.m_messages); |
| 242 | } |
| 243 | |
| 244 | if (hasBroadcast) |
| 245 | m_cv.notify_all(); |
| 246 | |
| 247 | while (!messages.empty()) |
| 248 | { |
| 249 | messages.front()(*context.m_processor); |
| 250 | messages.pop(); |
| 251 | } |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | template <typename... Args> |
| 256 | void Engine::PostMessage(Args &&... args) |