The POCO C++ library provides several classes that can be used to write multi-threaded programs in C++. The process of writing a multi-threaded program is similar to what you already know from Java. (There are few minor differences.) You need to perform the following steps.
  1. Derive a subclass from the class POCO::Runnable . Implement the inherited run() method.
  2. Create objects from the subclass you have derived. Each object corresponds to a runnable task.
  3. Create a ThreadPool, and start the runnable tasks using the method start(Runnable& target) of ThreadPool.
  4. You can use the method joinAll() of ThreadPool to wait for all threads in the pool to complete.

Here is a simple example.
  1. #include <iostream>
  2. #include "Poco/Runnable.h"
  3. #include "Poco/ThreadPool.h"
  4.  
  5. class Task : public Poco::Runnable {
  6. private:
  7.     int _id;
  8. public:
  9.     Task (int number) : _id(number) {}
  10.     void run(){
  11.         for (int i0i < 100i++){
  12.            std::cout << i << ") Task " << _id << " is working" << std::endl
  13.         }
  14.     }
  15. };
  16.  
  17. int main(){
  18.     Task task1(1);
  19.     Task task2(2);
  20.     Poco::ThreadPool pool;
  21.     pool.start(task1);
  22.     pool.start(task2);
  23.     pool.joinAll();
  24.     return 0;
  25. }

By default, the maximum thread pool size is 16. You can set this parameter according to your needs using an appropriate ThreadPool constructor call. After the creation of a ThreadPool, you can change the maximum capacity using the method
void addCapacity(int n);
n may be a positive or a negative number.

Default Arguments

One of ThreadPool's constructors is declared as follows:
ThreadPool(int minCapacity = 2, int maxCapacity = 16, int idleTime = 60, int stackSize = 0);

C++ allows the programmer to specify default values for arguments in the function's declaration. If arguments are missing in the invocation of the function, the default values are used. For example, invoking POCO::ThreadPool pool(2,10) sets the values of minCapacity to 2, maxCapacity to 10, and takes the default values for idleTime and stackSize, that are 60 and 0.

Basic synchronization

Basic synchronization is performed using the lock object POCO::RWLock . If several threads share a resource, they should also share a lock. When a thread needs to access the shared resources, it should acquire the lock first by executing the method writeLock() of POCO::RWLock . When it finishes with the resource, it releases the lock by executing the method unlock() . Only one thread is allowed to acquire the lock in any point in time. Other threads trying to acquire the lock when it is already acquired by some thread, will wait until it is released.

The next example corrects the synchronization problem from the previous example. (The shared resource is the output stream.)

  1. #include <iostream>
  2. #include "Poco/Runnable.h"
  3. #include "Poco/ThreadPool.h"
  4. #include "Poco/RWLock.h"
  5.  
  6. class Task : public Poco::Runnable{
  7. private:
  8.     int _id;
  9.     Poco::RWLock * _lock;
  10. public:
  11.     Task (int idPoco::RWLock * lock) : _id(id)_lock(lock) {}
  12.     void run(){
  13.         for (int i0i < 100i++){
  14.            _lock->writeLock()//acquire lock
  15.            std::cout << i << ") Task " << _id << " is working" << std::endl
  16.           _lock->unlock();  //release lock
  17.         }
  18.     }
  19. };
  20.  
  21. int main(){
  22.     Poco::RWLock lock;
  23.     Task task1(1, &lock);
  24.     Task task2(2, &lock);
  25.     Poco::ThreadPool pool;
  26.     pool.start(task1);
  27.     pool.start(task2);
  28.     pool.joinAll();
  29.     return 0;
  30. }

References

A Guided Tour of the POCO C++ Libraries

POCO Threading documentation