NVBIO
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
threads.h
Go to the documentation of this file.
1 /*
2  * nvbio
3  * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the NVIDIA CORPORATION nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #pragma once
29 
30 #include <nvbio/basic/types.h>
31 #include <nvbio/basic/numbers.h>
32 #include <nvbio/basic/atomics.h>
34 #include <queue>
35 
36 namespace nvbio {
37 
48 
51 
55 
58 
60 {
61 public:
62  ThreadBase();
63  ~ThreadBase();
64 
65  void set_id(const uint32 id) { m_id = id; }
66  uint32 get_id() const { return m_id; }
67 
69  void create(void* (*func)(void*), void* arg);
70 
72  void join();
73 
74 private:
75  struct Impl;
76 
77  uint32 m_id;
79 };
80 
101 template <typename DerivedThreadType>
102 class Thread : public ThreadBase
103 {
104 public:
106  void create() { ThreadBase::create( DerivedThreadType::execute, static_cast<DerivedThreadType*>(this) ); }
107 
109  void join() { ThreadBase::join(); }
110 
111 private:
113  static void* execute(void* arg)
114  {
115  DerivedThreadType* data = reinterpret_cast<DerivedThreadType*>( arg );
116  data->run();
117  return NULL;
118  }
119 };
120 
141 class Mutex
142 {
143 public:
144  Mutex();
145  ~Mutex();
146 
147  void lock();
148  void unlock();
149 
150 private:
151  struct Impl;
152 
154 };
155 
180 {
181 public:
182  ScopedLock(Mutex* mutex) : m_mutex( mutex ) { m_mutex->lock(); }
183  ~ScopedLock() { m_mutex->unlock(); }
184 
185 private:
186  Mutex* m_mutex;
187 };
188 
190 template <typename WorkItemT, typename ProgressCallbackT>
192 {
193 public:
194  typedef WorkItemT WorkItem;
195  typedef ProgressCallbackT ProgressCallback;
196 
198  WorkQueue() : m_callback(), m_size(0u) {}
199 
201  void push(const WorkItem work) { m_queue.push( work ); m_size++; }
202 
204  void locked_push(const WorkItem work)
205  {
206  ScopedLock block( &m_lock );
207  m_queue.push( work ); m_size++;
208  }
209 
211  bool pop(WorkItem& work)
212  {
213  ScopedLock block( &m_lock );
214  if (m_queue.empty())
215  return false;
216 
217  work = m_queue.front();
218  m_queue.pop();
219 
220  m_callback( m_size -( uint32)m_queue.size() - 1u, m_size );
221  return true;
222  }
223 
225  void set_callback(const ProgressCallback callback) { m_callback = callback; }
226 
227 private:
228  ProgressCallback m_callback;
229  std::queue<WorkItem> m_queue;
230  Mutex m_lock;
231  uint32 m_size;
232 };
233 
235 inline uint32 balance_batch_size(uint32 batch_size, uint32 total_count, uint32 thread_count)
236 {
237  // How many batches we'd get with the proposed batch_size
238  const uint32 batch_count = util::divide_ri(total_count, batch_size);
239  // How many rounds we'd need for those batches
240  const uint32 rounds = util::divide_ri(batch_count, thread_count);
241  // Might as well assume all threads should work, and see how many batches
242  // they would consume
243  const uint32 bal_batches = rounds * thread_count;
244  // So that the batch size that will attain it, is computed as follows
245  return util::divide_ri(total_count, bal_batches);
246 }
247 
248 void yield();
249 
252 
253 } // namespace nvbio