title: Windows API Thread Pool simple example
body: <p>[EDIT: thanks to MSalters answer and Raymond Chen's answer to <a href="https://stackoverflow.com/questions/8393990/interlockedincrement-vs-entercriticalsection-counter-leavecriticalsection">InterlockedIncrement vs EnterCriticalSection/counter++/LeaveCriticalSection</a>, the problem is solved and the code below is working properly. This should provide an interesting simple example of Thread Pool use in Windows]</p>
  
  <p>I don't manage to find a simple example of the following task. My program, for example, needs to increment the values in a huge std::vector by one, so I want to do that in parallel. It needs to do that a bunch of times across the lifetime of the program. I know how to do that using CreateThread at each call of the routine but I don't manage to get rid of the CreateThread with the ThreadPool.  </p>
  
  <p>Here is what I do :</p>
  
  <pre><code>class Thread {
  public:
      Thread(){}
      virtual void run() = 0 ; // I can inherit an "IncrementVectorThread"
  };
  class IncrementVectorThread: public Thread {
  public:
     IncrementVectorThread(int threadID, int nbThreads, std::vector&lt;int&gt; &amp;vec) : id(threadID), nb(nbThreads), myvec(vec) { };
  
     virtual void run() {
          for (int i=(myvec.size()*id)/nb; i&lt;(myvec.size()*(id+1))/nb; i++)
            myvec[i]++; //and let's assume myvec is properly sized
      }
     int id, nb;
     std::vector&lt;int&gt; &amp;myvec;
  };
  
  class ThreadGroup : public std::vector&lt;Thread*&gt; {
  public:
      ThreadGroup() { 
           pool = CreateThreadpool(NULL);
           InitializeThreadpoolEnvironment(&amp;cbe);
           cleanupGroup = CreateThreadpoolCleanupGroup();
           SetThreadpoolCallbackPool(&amp;cbe, pool);
           SetThreadpoolCallbackCleanupGroup(&amp;cbe, cleanupGroup, NULL);
           threadCount = 0;
      }
      ~ThreadGroup() {
           CloseThreadpool(pool);
  }
      PTP_POOL pool;
      TP_CALLBACK_ENVIRON cbe;
      PTP_CLEANUP_GROUP cleanupGroup;
      volatile long threadCount;
  } ;
  
  
  static VOID CALLBACK runFunc(
                  PTP_CALLBACK_INSTANCE Instance,
                  PVOID Context,
                  PTP_WORK Work) {
  
     ThreadGroup &amp;thread = *((ThreadGroup*) Context);
     long id = InterlockedIncrement(&amp;(thread.threadCount));
     DWORD tid = (id-1)%thread.size();
     thread[tid]-&gt;run();
  }
  
  void run_threads(ThreadGroup* thread_group) {
      SetThreadpoolThreadMaximum(thread_group-&gt;pool, thread_group-&gt;size());
      SetThreadpoolThreadMinimum(thread_group-&gt;pool, thread_group-&gt;size());
  
      TP_WORK *worker = CreateThreadpoolWork(runFunc, (void*) thread_group, &amp;thread_group-&gt;cbe);
      thread_group-&gt;threadCount = 0;
      for (int i=0; i&lt;thread_group-&gt;size(); i++) {
          SubmitThreadpoolWork(worker);
       }  
       WaitForThreadpoolWorkCallbacks(worker,FALSE);  
       CloseThreadpoolWork(worker);   
  }       
  
  void main() {
  
     ThreadGroup group;
     std::vector&lt;int&gt; vec(10000, 0);
     for (int i=0; i&lt;10; i++)
        group.push_back(new IncrementVectorThread(i, 10, vec));
  
     run_threads(&amp;group);
     run_threads(&amp;group);
     run_threads(&amp;group);
  
     // now, vec should be == std::vector&lt;int&gt;(10000, 3);       
  }
  </code></pre>
  
  <p>So, if I understood well :<br>
  - the command CreateThreadpool creates a bunch of Threads (hence, the call to CreateThreadpoolWork is cheap as it doesn't call CreateThread)<br>
  - I can have as many thread pools as I want (if I want to do a thread pool for "IncrementVector" and one for my "DecrementVector" threads, I can).<br>
  - if I need to divide my "increment vector" task into 10 threads, instead of calling 10 times CreateThread, I create a single "worker", and Submit it 10 times to the ThreadPool with the same parameter (hence, I need the thread ID in the callback to know which part of my std::vector to increment). Here I couldn't find the thread ID, since the function GetCurrentThreadId() returns the real ID of the thread (ie., something like 1528, not something between 0..nb_launched_threads).  </p>
  
  <p>Finally, I am not sure I understood the concept well : do I really need a single worker and not 10 if I split my std::vector into 10 threads ?</p>
  
  <p>Thanks!</p>