user304584
user304584

Reputation: 507

How can I create my own thread pool on legacy c++?

I am facing a problem because of high overhead of pthread_create. I have looked the internet for a good threadpool library, but I didn't find one that suits my project, or they simply did not work.

I am quite new to c++, and my programming skills are pretty basic, but good. I programmed a lot (over 5 years), I just did not do any object oriented projects or even used data structures.

I would really appreciate any material or guides that can help me get the experience and knowledge needed to create my own thread pool.

Due to constraints in my current project, I will work on normal c++ (not C++11) on a windows 10 (mingw32) and I have to avoid using any boost libraries.

as requested: About the problem:

I am writing a computational expensive project. I want to make it run faster, so I decided to use pthreads. The problem, however, is that the thread creation is inside a loop, and pthread_create is called 64 times.

After a lot of research and trying I figured out that threadpools are the solution here, but I spent over 3 days getting the implementations I found online to work, but to no avail, so I decided to write my own thread pool implementation.

About an example of the code you can check: How can I reduce the effect of pthread_join. Mingw32, c++

But there I realized its the thread create, not thread_join that causes the performance to worsen.

Upvotes: 0

Views: 400

Answers (1)

SergeyA
SergeyA

Reputation: 62563

Despites some comments over there, basic thread pools are not that complicated. They are simpler than good logger, for instance :)

First, a couple of statements.

  • pthread_create is VERY lightweight. It is unlikely it is a real bottleneck. If your compulation time is comparable with the time it takes to create a thread, you might not need a thread to begin with.
  • C++11 is the NORMAL C++. C++03 is referred to as ARCHAIC. I strongly urge you to rethink 'constraints' of your project (since you do not seem to be using external libraries, ABI incompatibility should not a problem for you), and forgo an 11 years old, outdated and inadequate compiler.

Now, to thread pools. The basic thread pool contains of 3 major parts: incoming message queue, outgoing message queue and a bunch of threads servicing those queues. Depending on the design, those messages might be either a real message (i.e. string saying "dear thread, please compute 5 + 10"), or it can be a callable thing, which thread just calls. A type-erased function object works best here. So, when the message is a text, thread function will have a bunch of if() statements to handle different messages, when it is a callable, it will simply call this callable. Text messages are easier to maintain, since you have everything you need to care about in the text itself. Callable objects, on the other hand, have a lifetime, which you should be thinkig of - for instance, putting local variables as callables will be a guaranteed disaster.

The other piece is the message queue itself. First of all, there are two viable design choices - every thread has it's own queue, or there is a shared queue to be used by all threads. The benefits of the first is that there is no contention on the queue - there is one reader and one writer. Shared queue has contention, but the benefit is that it provides for natural load balancing - threads will simply pick up messages as they are ready to process a new one.

Lockless queue is usually a good choice to be used as a message queue.

Upvotes: 3

Related Questions