Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
Hello,
 
I have an event handler in the main thread, which receive events from outside process. And upon the receipt of a new event, a new thread is created to handle the event. The problem is whenever I create a new thread inside the event handler, it will be destroyed when the event handler finishes. To solve this problem, after the creation of the thread, I am calling its join function, but this will cause the main thread which has the event handler to block its execution until the thread finishes its job. And actually this will be converted back to a single thread case. Where for each event, a new thread is created when the previous, thread is destroyed.
 
For more explanation ,please check the code below:
void ho_commit_indication_handler(message &msg, const boost::system::error_code &ec)
{
.....
}
 
void event_handler(message &msg, const boost::system::error_code &ec)
{
    if (ec)
    {
        log_(0, __FUNCTION__, " error: ", ec.message());
        return;
    }
 
    switch (msg.mid())
    {
        case n2n_ho_commit:
        {
            boost::thread thrd(&ho_commit_indication_handler, boost::ref(msg), boost::ref(ec));
            thrd.join();
        }
        break
    }
};
So my question is, how to handle each event through a separate thread and keep the thread alive even if the main thread exits the event_handler?
 
Note: I am using Boost 1.49 library
 

If what you're saying is correct. So why this happens in the following example:

#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <chrono>

void foo()
{
    std::chrono::milliseconds dura( 2000 );
    std::this_thread::sleep_for( dura );
    std::cout << "Waited for 2Sec\n";
}
 
void bar(int x)
{
    std::chrono::milliseconds dura( 4000 );
    std::this_thread::sleep_for( dura );
    std::cout << "Waited for 4Sec\n";
}
 
int main()
{
  std::thread first (foo);
  std::thread second (bar,0);
 
  return 0;
}
 
 
You're saying the thread is alive. I get the following output:
terminate called without an active exception
Aborted (core dumped)

This happened because the main thread has terminated, before the thread terminations
 
Thanks a lot.
Posted 15-Mar-14 17:05pm
Edited 16-Mar-14 8:58am
v5
Comments
Sergey Alexandrovich Kryukov at 15-Mar-14 22:08pm
   
If you is Boost, you are not using C++/CLI, you are using C++.
—SA
Mr.HA-AS at 15-Mar-14 22:15pm
   
OK, I modified it.
Sergey Alexandrovich Kryukov at 15-Mar-14 22:17pm
   
Good. And in the meanwhile, I answered.
—SA
Sergey Alexandrovich Kryukov at 15-Mar-14 22:18pm
   
There is no issue. The code simply makes no sense. Perhaps I could advise what to do if you explain your ultimate purpose.
But I would rather advise to learn the threading in general...
—SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

Here is my opinion: Threading is a brutally difficult topic and unfortunately I have to agree with Sergey that you don't get it. But don't be disappointed, it takes years even for the best programmers to grasp it and some (most) programmers never grasp it (and sometimes depending on their specialty, language/paradigm of their choice they may not need to know about threading at all...). It isn't enough that threading is hell difficult, you will find a lot of material/tutorial related the threading and 99% of them is terrible and ugly and uses antipatterns.
 
Some hints:
- A well written multithreaded program always joins the created threads and usually a thread is created/joined by the same "owner" thread (that is usually the main thread). I is totally pointless/needless to create a thread on one thread and then joining it on another. Its better to leave the management of thread lifecycle to a "manager" thread that is usually the main thread or in other cases you can hide the thread lifecycle management inside a thread pool object.
- Most programs need only a few threads and these thread can be created on program startup and can be joined/destroyed at program exit.
- Every multithreaded program can be written this way, if you need detached threads then your threading design is not good. Post some multithreaded problems and people will help in putting together a good design/architecture to solve your problem. If someone uses thread manipulation functions other than "crreate" and "join" then their design is also bad.
 
BTW, if you are using a new compiler then you can use threading classes from the std lib instead of boost. Unfortunately the std lib also contains totally unnecessary threading functions/operations that confuse people and encourage antipatterns.
 
EDIT: About your actual problem:
You are creating one thread per client and you simply don't know when to join the threads... Actually you should neither create nor join those threads... The following statement will be a very big game changer here:
 
You shouldn't have more **active**/performance critical threads than the number of cores in your cpu. Even if your client threads are not cpu grinding ones you MUST somehow limit the number of clients to serve in parallel to protect your server from blowing up in lack of resource (for example because of running out of socket handles or memory to create new threads even if they are idle). How to do this???
 
Just create a thread pool with a fixed number of threads at program startup and stop/destroy it at program exit. The number of threads can usually be tweaked at threadpool creation. A threadpool consists of several threads and a common job queue. Every thread does the following in a loop: they pull out a job from the queue and execute it, if the queue is empty then they wait until a job arrives. (Offtopic: I usually ask the thread pool threads to terminate by putting NUM_THREADS number of NULL jobs to the queue...).
 
OK, A thread pool solves how/when to create/join the threads but how can we utilize it in case of your problem: We define our job as a "ServeClient" job. You create this serve-client job on your accept (maybe the main) thread and you pass all parameters (eg: socket, remote address, ...) of the client to the constructor of this job. Then all you do on the main thread is putting this "ServeClient" job to the queue of the thread pool. At some later point a pool thread will grab out this "ServeClient" job from the queue and call its "Execute" method. Then in this execute method you can perform everything that has to be done for this client. When the client is served then as a last step the Execute method of the job can destroy the job object and the thread can return from Execute to grab out the next ServeClient job from the queue.
 
- OK but what to do if the servicing of the client lasts for a long time and some other ServeClient jobs are waiting in the queue and maybe time out: Then you can create more threads
- What if I have even more clients then the number of threads??? You have to draw the line somewhere... You can not accept/serve more than MAX_CLIENTS number of clients if you don't want your server to blow up as a result of too many connections/threads/resources. By the way: the multithreaded one-thread-per-client approach doesn't really work effectively after a few hundred clients, in case of thousands of clients you have to perform the network IO asynchronously (IOCP/epoll/kqueue) on 1 or a few threads (async IO doesn't need many threads and the OS does the necessary threading for you in case of IO in an optimized way for the current platform) and when a request fully arrived using async IO then you have to perform only the actual server side logic on a thread pool in order to avoid blocking the async IO thread.... There are so many countless setups to solve different scenarios that it is impossible to list all of them. Start writing servers and after a few ten servers you will start to grasp what I was talking about.
 
For now limit the max number of clients for example to 100. If you want to be able to serve 100 clients in parallel then create a threadpool with a max thread count of 100. A normal nice healthy thread pool has the following operations available:
- CreatePool(max_thread_count)
- AddJob(job)
- StopAndJoinAllThreads()
 
Any more operations are redundant. Don't use other thread pool operations, everything can be solved with this and this threadpool interface can be implemented even on the dumbest platform that supports threads in any way. If you need any other operations then it simply means that your design is bad. The same is true for thread operations: If you need something else then create or join then you are doing something in a wrong way. You will see a lot of redundant ugly/evil functions in threading apis (like std::thread/pthread implementations/winapi), for example: TerminateThread, "trylock", ... All these are totally unnecessary and sometimes very dangerous function calls in case of an application and they are just evil because of making attractive some antipatterns and solutions that look good at first glance, maybe even at second glance for the unexperienced. If you cant solve a problem with basic threading operations then ask for a solution for your problem on a forum. Normall you should be able to solve any problems just with thread pools and by placing jobs into thread pools. In worst case you need 2 thread pools: One that performs short executing jobs on at most as many thread as the number of cores, and additionally another thread pool that runs long running operations, optionally this thread pool can be a special one that creates a thread only when you add a long running job into the pool...
 
In my opinion you will never need to increase the number of active threads in a pool, that is simply useless. You can actually decrease the number of active threads temporarily by N by putting N number of blocking jobs into the queue of the pool and what these special jobs do is blocking the thread until you set an event in the job...
 
What to do if you don't want to precreate 100 threads for 100 clients? Then you can still write a special threadpool that creates a thread only when you call AddJob() but in my opinion this is not a good idea. Its usually better to precreate threads at startup and keep them till program exit. Thread creation is an expensive operation (especially if you don't limit the stack sizes) and usually impossible to handle gracefully if it fails at the middle of program (for example server program) execution. Its better to fail this way either at program startup or never...
 
I have 100 threads and I'm just placing ServeClient jobs into the threadpool queue as connections arrive... How to limit the number of accepted clients if I know that the servicing of a client takes long on a thread and it has no point of putting any more ServeClient jobs to the queue???
In this case you can manage a counter in the destructor of ServeClient jobs and in your client acceptor (main) thread. You are just incrementing this counter atomically (InterlockedIncrement/Decrement or std atomic stuff). In the destructor of your ServeClient job you are just decrementing this counter atomically. On your main thread you are just incrementing it. The InterlockedIncrement operation always returns the result of the increment. On your main thread when you accept a connection you increment this counter and if the result is >100 then you just close the socket (maybe send a too many clients message if you are doing it gracefully) and atomic decrement back the counter and accept the next client. (You can also sleep while you have 100 active clients with a bit more complex solution...). If your main thread increments the counter and the result is <=100 then just create the ServeClient job for the connection and put it to the queue.
 
Do you get it now? Smile | :)
 
EDIT #2: Detached threads: Using detached threads the way you are using them (creating them and letting them go into the wild without supervision...) is definitely a wrong solution. I can still tell you a case where I use them. I mentioned you that sometimes I use a special threadpool that creates a thread for every job exactly when you add the job to the pool and the new thread executes the job and then terminates/disappears by itself. Besides this when you try to terminate/delete the threadpool itself you must be able to join/wait all currently running threads (in the StopAndJoinAllThreads() method of the threadpool).
Note: If you create a joinable posix thread (including the std::thread that has this same rule) then you MUST join it exactly once. If you don't do this then you leak a small piece of memory that holds the exitcode (and maybe some other info) of the thread. Note that in a threadpool where the thread terminates by itself after executing the job the thread cant simply join itself to avoid this leak and you don't have another thread in the pool that could do this thread-handle cleanup (ok, some dump threadpool implementations have this so called "manager thread", avoid such dumb implementations with a "manager thread"). For this reason it is better to create this thread as detached by default (with pthread api you can immediately create it as detached, with std::thread and winapi you can detach/close the handle after thread creation). OK, but now how to handle the case when the main thread wants to delete the thread pools before program exit? It must somehow join the still running threads in the special thread pool! For this reason you can keep an atomic counter in the threadpool that is initialized to zero along with a triggerable event set to false by default. You must also make sure that when you exit your main thread there are no alive threads that are using the threadpool when you are about to call StopAndJoinAllThreads() on the thread pool.
 
What your threadpool.StopAndJoin() does is the following:
- AtomicDecrement() the counter and if the result is -1 then there are not running threads.
- If the result of AtomicDecrement() is zero or more than there are at least one threads that are still running. In this case you have to wait for the event to be fired.
 
Every time a new job is added you have to do the following:
- AtomicIncrement() the counter, create the thread and give it the job.
 
On thread exit the thread should do the following before actually returning from its low level thread function:
- AtomicDecrement() the counter and if it is -1 then it means that threadpool.StopAndJoin() is wating and this is actually the last thread that terminates so lets set the event object on which StopAndJoin() is waiting.
 
As you see here I used a detached thread but I couldn't tell you another scenario where I'm actually utilizing detached threads and even in this case they are hidden inside a thread pool and actually all of them are guaranteed to be joined before threadpool destruction.
 

Some other bad news came to my mind about dumb threadpools with manager threads: The threadpools that usually come with a manager threads are usually make use of this special manager thread not because of handle cleanup like in case of the previous problem but because they are trying to create an overcomplicated hyper-super-all-in-one general threadpool that can actually execute both short and long running jobs. In this case you have a problem that if a user tries to add a lot of long running threads then the user can reach the threadcount with long running jobs and this causes some short running jobs in the queue to "starve/timeout". For this reason the super-intelligent manager thread detects this (actually it detects that no thread has finished in the last x milliseconds) and it spawns some new threads. Why is this bad? As I said a thraedpool has to know only these: Create(maxthreads), addjob(job), StopAndJoin(). Thread programming is complicated enough even with this little functionality, putting a lot of super-intelligent AI code with manager threads into a threadpool increases complexity a lot and almost all of these implementations suffer of race conditions and bugs that will be found by noone because those who know what thread programming is will never look at those implementations and those who chose them are actually choosing them because they dont know much about multithreading. OK, how to solve the previous problem elegantly. As I told you in such a scenario you have to use two pools: one for short tasks (with at most numcores number of threads) because short task pools usually grind the cores and you should have a threadpool for long tasks - in special cases you can have even more if you have a good reason. You don't need artificial intelligence to decide when to create a thread. You can decide what jobs are short and long when you are writing your program. If you cant then: 1.) dont write threaded code. 2.) learn multithreading before writing multithreaded code in a production env. Smile | :)
  Permalink  
v9
Comments
Mr.HA-AS at 17-Mar-14 7:49am
   
Thanks a lot for your answer. But from what I got from your answer using thread.detach() is a bad idea? But why?
It's already a part of the new standard library in c++. And actually it solved my problem for the event_handler. In the reference which describes the detach in c++, they didn't mention anything about this issue.
 
I am using boost, because my application needs to be cross-platform, that's why.
 
I also suggested to Sergey to have Thread Pool in the main thread, since this is the main thread and shouldn't be destroyed until the end, but he insisted in telling me that I don't understand thread. And he didn't gave me any good answer, I've provided the code and asked him to explain but no way.
pasztorpisti at 17-Mar-14 16:23pm
   
The standard library is also crossplatform as boost and the std lib actually ships with the new compilers out of the box. If you don't have to be compatible with old compilers then using std is often a better idea, of course there are some exceptions to this. Anyway, boost is a playground where people experiment with things and many-many std things are often just libs coming originally from boost where it was tested out and became mature. Coming back to your original problem: its actually a classic one and brings up many basic problems you don't even think about currently as I see, I will write more about these as the continuation of my answer.
Mr.HA-AS at 17-Mar-14 19:25pm
   
Thanks a lot for your great explanation. I totally agree with you regarding the creation of the a new thread is cost in terms of performance like memory usage.
 
Let me explain to you my deployment scenario. In my case I am running my application on a server blade with 16 cores and 32GRAM. And for the users request, they are actually a handover requests to make a handover from one BaseStation to other BaseStation. And from the user perspective, the handover operation is very crucial and needs to be served as fast as possible, otherwise the session will be dropped, and the user has to establish a new session again. That's why I was using a thread per client request.
Also I won't have a high number of users per minute, and the thread live won't last for a long time it's just numbers of milliseconds.
 
But according to what you have just said, even detach command is a part of the standard library, but it's not a standardized operation for the threads, and I should avoid using it.
 
So according to what I just said, you still suggest me to replace my current design with your suggested design for thread pool and job queue, or is there even any better solution than that?
 
And finally I would really like to thank you a lot for great efforts in clarifying everything to me :)
pasztorpisti at 17-Mar-14 19:47pm
   
You are welcome. :-) The big question in this case: Can you determine the maximum number of clients? As I see you can. If yes then adjust the number of threads in the threadpool (and also the MAX_CLIENTS constant/variable) to this size, maybe a bit more and you are done. Working with a fixed number of threads is usually better than "creating them on the fly". I can not tell you what is the right solution in your case because it can be found out only by trying different solutions with different setups/tweaks and by measuring the performance according to some parameters that are important for you (latency, throughput, any occasional hangup per client, ...). Actually you should write both a preforked/multithreaded and an async server and try both of them with different setups. In case of short running jobs an async IO server with threadpool (around numcore number of threads) can also do wonders... The asnyc thread/threads are just reading the requests from multiple sockets and they are passing the incoming request to the threadpool that grinds all the requests at most on as many threads as the available cores, maybe a few threads less to give some power for the OS and IO threads... lets tweak it. At the same time when a threadpool job (a served request) is done thent he result can be passed back to the async IO thread that can put the result into the send queue of the socket. Use IOCP/epoll/kqueue depending on the os to do the IO or use a crossplatform library that uses one of these to do the job depending on the platform. What I don't like in the multithreaded version is that if you have for example 100 connections and accidently all threads are working heavily then running 100 or more very active threads on 16-24 cores is not effective. If the serving of the clients is short and can be broken down into short jobs then using async io on 1-2 threads + a threadpool with a few threads is usually the winner. Sometimes with only a few clients (for example in case of a simple http server) a multithreaded server can outperform an async one but this advantage evaporates quickly as the number of clients grow.
Mr.HA-AS at 17-Mar-14 20:08pm
   
Thanks again, as you said I will try different solutions with different setups. Because at the end what is important to me is the E2E Delay ,and Latency. I will come back to you later when I finished testing and tell you about the result and what I found out.
For the current time, I am still in the implementation phase of my project.
pasztorpisti at 17-Mar-14 20:18pm
   
I also added some comments about a use case for detached threads, and meanwhile some thoughts came to my mind about alternative implementations with an silly anitpattern... When you are tweaking the servers you may have to play around with socket options too. You can improve latency for example by turning off nagle you can tweak recv/send buffer sizes although this one usually helps only with high volumes of data... Check out the setsockopt doc pages. RTFM, its boring but needed. :-)
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

The question makes no sense: the threads are always executed outside the function which created them. More exactly, threads and functions are orthogonal: any function can be executed be several thread, each thread can call several functions (as in single-threaded programming). The structure of the calls/returns, function parameters and local variables are based on the stack; and each thread has its own separate thread.
 
Now, let's see what you are doing. You create some thread and then join the same thread. It means that the calling thread, the one which called the function join is put in the wait state, that is, switched of and not scheduled back to execution until it is waken up. One of the events to wake up the working thread is completion of the thread you are trying to join. In other words, calling thread is sleeping, another thread is being executed to the very end, and than calling thread resumes the execution. It simply means that the two threads work one after another, never do anything in parallel. In turn, it means that you totally defeat the purpose of threading.
 
I don't want to answer "How to keep threads working outside the the function which created them". This is not what you want. I may only think that you want it, but in fact, this question does not make any sense at all. What you really want is to understand what are threads, their purpose and usage. Right now, you don't have a clue, not even close. I would advise to learn about it; this is very important.
 
—SA
  Permalink  
v2
Comments
Mr.HA-AS at 15-Mar-14 22:33pm
   
I know about the threads, but I believe is my problem is as following:
Consider the previous code without having the join function being executed after the creation of the thread. The newly created thread will start to work in parallel with the function that created it. But when the event_handler reaches the end, it will call the default destructor of the newly created thread which is working in parallel.
 
And this is what actually happened with me, the program crashed when I did this.
 
So my question is how to keep the thread alive? what I think is like to have a thread pool outside the scope of the function, am I correct or not?
Sergey Alexandrovich Kryukov at 15-Mar-14 23:03pm
   
Maybe "knowing about the threads" is not enough. You don't need to care about crashing, because the whole idea to start thread and join it makes no purpose. The question is not how to keep thread alive. It is alive. When join call is returned, it happens then the thread is complete, which is defined by the thread method. There is nothing to "keep alive".
—SA
Mr.HA-AS at 16-Mar-14 10:23am
   
Check, what I posted now please.
Sergey Alexandrovich Kryukov at 16-Mar-14 12:15pm
   
This "code" is even worse. I repeat: you need to learn threading. You did not explain your ultimate goals and do not understand threading, you are not digesting my help.
 
But okay, you formally accepted you own non-solution. So, no more help for you, as you are not playing nice. You think you got the solution, be it your way then.
 
—SA
Mr.HA-AS at 16-Mar-14 13:57pm
   
You're not getting what I want. Other threads were more helpful. And explained to me what I wanted.
The solution is to use detach() command. And you should keep the main thread not matter what.
So thanks for being a nice and helpful person.
Sergey Alexandrovich Kryukov at 16-Mar-14 14:25pm
   
If I'm not getting something, this is because you are not explaining it.
You are very welcome; sorry I cannot tell you more at this moment.
—SA
pasztorpisti at 16-Mar-14 23:04pm
   
+5, there are some really good hints here
Sergey Alexandrovich Kryukov at 16-Mar-14 23:11pm
   
Thank you very much,
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 OriginalGriff 8,284
1 Sergey Alexandrovich Kryukov 7,327
2 DamithSL 5,614
3 Manas Bhardwaj 4,986
4 Maciej Los 4,920


Advertise | Privacy | Mobile
Web02 | 2.8.1411023.1 | Last Updated 17 Mar 2014
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100