Using the Ace_task of Ace and other classes to realize thread pool method _c language

Source: Internet
Author: User
Tags arithmetic operators message queue mutex sleep
This code should be an example of ACE, but I think it is very good, so share with you.
The comments are very detailed.
Header File
Copy Code code as follows:

#ifndef Thread_pool_h
#define Thread_pool_h
/* In order to implement a thread pool, and we have to have an object
Can create a thread. The ace_task<> is the basis for doing just
Such a thing. */
#include "Ace/task.h"
Add by Ychen 20070714 below
#include "ace/mutex.h"
Add by Ychen 20070714 above
#if!defined (ace_lacks_pragma_once)
# pragma once
#endif/* ace_lacks_pragma_once * *
/* We need a forward reference for Ace_event_handler so
Enqueue () method can accept a pointer to one. */

Class Ace_event_handler;
/* Although we modified the rest of our
Thread pool implementation, if you look closely ' ll
Changes were rather minor. The "ACE way" is generally to create a
Helper object that abstracts away the details not relevant to your
Application. That's what I ' m trying to does here by creating the
Thread_pool object. */
Class Thread_pool:public Ace_task<ace_mt_synch>
{
Public
typedef ace_task<ace_mt_synch> inherited;
/* Provide an enumeration for the default pool size. By doing this,
objects can use the value when they want a default. */
Enum size_t
{
Default_pool_size_ = 1
};
Basic Constructor
Thread_pool (void);
/* Opening The thread pool causes one or more threads to IS
Activated. When activated, they all execute the SVC () method
Declared below. */
int open (int pool_size = default_pool_size_);
/* Some Compilers'll complain that we open () above attempts to
Override a virtual function in the BaseClass. We have no
Intention of overriding that is but in order to keep the
Compiler quiet we have to add-as a pass-thru to the
BaseClass method. */
virtual int open (void *void_data)
{
Return Inherited::open (Void_data);
}
/*
*/
virtual int close (U_long flags = 0);
/* To use the thread pool, your have to put some unit of work into
It. Since we ' re dealing with event handlers (or at least their
Derivatives), I ' ve chosen to provide a enqueue () method
Takes a pointer to a ace_event_handler. The handler ' s
Handle_input () method would be called, so your object has to know
When it's being called by the thread pool. */
int Enqueue (Ace_event_handler *handler);
/* Another handy ACE template is ace_atomic_op<>. When
Parameterized, this allows be to have a thread-safe counting
Object. The typical arithmetic operators are all internally
Thread-safe so can share it across threads without
Worrying about any contention issues. */
typedef Ace_atomic_op<ace_mutex, int> counter_t;

Protected
* We Svc () method would dequeue the Enqueued event handler objects
and invoke the Handle_input () method in each. Since we ' re likely
Running in more than one thread, idle threads can take work from
The queue while other threads are busy executing handle_input () on
Some object. */
int svc (void);
/* We Use the atomic op to keep a count of the number of threads in
which we SVC () is running. This is particularly important
When we want to close () it down! */
counter_t Active_threads_;
};
#endif/* Thread_pool_h * *

Implementation file
Copy Code code as follows:

Thread_pool.cpp,v 1.9 1999/09/22 03:13:42 jcej EXP
#include "thread_pool.h"
/* We need this header so, we can invoke Handle_input () on the
Objects we dequeue. */
#include "Ace/event_handler.h"
* All we do are initialize our active thread counter. */
Thread_pool::thread_pool (void)
: Active_threads_ (0)
{
}
/* We open () is a thin disguise around the ace_task<>
Activate () method. by hiding activate () into this way, the users of
Thread_pool don ' t have to worry about the thread configuration
Flags. */
Int
Thread_pool::open (int pool_size)
{
Return This->activate (thr_new_lwp| Thr_detached, pool_size);
}
/* Closing The thread pool can be a tricky exercise. I ' ve decided to
Take an easy approach and simply enqueue a secret
Thread we have active. */
Int
Thread_pool::close (U_long flags)
{
Ace_unused_arg (flags);
/* Find out how many threads are currently active *
int counter = Active_threads_.value ();
/* For each one of the active threads, enqueue a "null" event
Handler. Below, we ' ll teach our Svc () method, "null" means
"Shutdown". */
while (counter--)
This->enqueue (0);
/* As each SVC () method exits, it would decrement the active thread
Counter.  We just wait here for it to reach zero. Since we don ' t
Know how long it'll take, we sleep for a quarter of a second
Between tries. */
while (Active_threads_.value ())
Ace_os::sleep (ace_time_value (0, 250000));
return (0);
}
/* When a object wants to does work in the pool, it should call the
Enqueue () method. We introduce the ace_message_block here but,
Unfortunately, we seriously misuse it. */
Int
Thread_pool::enqueue (Ace_event_handler *handler)
{
/* A ace_message_block is a chunk of data. Your put them in
Ace_message_queue. Ace_task<> has a ace_message_queue built in.
In fact, the parameter to ace_task<> be passed directly to
Ace_message_queue. If you look back in our header file, you ll
That's we used Ace_mt_synch as the parameter indicating that we want
multithread Synch safety. This is allows us to safely put
Ace_message_block objects into the message queue in one thread and
Take them out in another. */
/* A ace_message_block wants to have char* data. We don ' t have
that. We could cast our ace_event_handler* directly to a char*
But I wanted to being more explicit. Since Casting pointers around
is a dangerous thing, I ' ve gone out the My way this is very
Clear about what we ' re doing.
First:cast the handler pointer to a void pointer. Can ' t do
Any useful work on a void pointer
We ' re making the pointer unusable.
Next:cast The void pointer to a char pointer the Ace_message_block would accept. */
void *v_data = (void *) handler;
Char *c_data = (char *) v_data;
Ace_message_block *MB;
/* Construct a new ace_message_block. For efficiency, might
Want to preallocate a stack of these and reuse them. For
Simplicity, I ' ll just create what I need as I need it. */
Ace_new_return (MB,
Ace_message_block (C_data),
-1);
/* We PUTQ () is a wrapper around one of the enqueue methods
Of the ace_message_queue that we own. Like all good methods, it
Returns-1 if it fails for some reason. */
if (this->putq (MB) = 1)
{
/* Another Trait of the Ace_message_block objects is that they
are reference counted. Since they ' re designed to be passed
Around between various objects in several threads we can ' t
Just delete them whenever we feel like it. The release ()
Method was similar to the Destroy () method we ' ve used
Elsewhere. It watches the reference count and would delete the
Object when possible. */
Mb->release ();
return-1;
}
return 0;
}
/* The "guard" concept is very powerful and used throughout
Multi-threaded applications. A Guard normally does some operation
On ' An object ' at construction and the ' opposite ' operation at
Destruction. For instance, while you guard a mutex (lock) object,
The guard would acquire the lock on construction and release it
Destruction. In this way, your can simply let the guard go
Out of scope and know this lock is released.
Guards aren ' t only useful for locks however. In this application
I ' ve created two guard objects for quite a different purpose. */
/* The Counter_guard is constructed with a reference to the thread
Pool ' s active thread counter. The guard increments the counter
When it was created and decrements it at destruction. By creating
One of these in Svc (), I know that the counter would be decremented
No matter how or where SVC () returns. */
Class Counter_guard
{
Public
Counter_guard (thread_pool::counter_t &counter)
: Counter_ (counter)
{
++counter_;
}
~counter_guard (void)
{
--counter_;
}
Protected
thread_pool::counter_t &counter_;
};
/* My message_block_guard is also a little non-traditional. It
doesn ' t do anything in the constructor but it ' s destructor ensures
The message block ' s release () is called. This is a
Cheap way to prevent a memory leak if I need an additional exit
Point in Svc (). */
Class Message_block_guard
{
Public
Message_block_guard (Ace_message_block *&mb)
: Mb_ (MB)
{
}
~message_block_guard (void)
{
Mb_->release ();
}
Protected
Ace_message_block *&mb_;
};
/* Now we come to the SVC () method. As I said, this is being executed
In each thread of the Thread_pool. Here we are pull messages off of
We built-in ace_message_queue and cause them to do work. */
Int
Thread_pool::svc (void)
{
/* The GETQ () method is takes a reference to a pointer. So ... we need
A pointer to give it a reference. */
Ace_message_block *MB;
/* Create The guard for our active thread counter object. No matter
Where we choose to return () from Svc (), we are know that the
Counter would be decremented. */
Counter_guard Counter_guard (Active_threads_);
/* Get messages from the queue until we have a failure. There ' s No
Real good reason for failure so if it happens, we leave
Immediately. */
while (THIS-&GT;GETQ (MB)!=-1)
{
/* A successful GETQ () would cause "MB" to "a" valid
Refernce-counted Ace_message_block. We Use our Guard object
Here we are ' re sure to call the release ()
Message block and reduce it ' s reference count. Once The Count
reaches zero, it'll be deleted. */
Message_block_guard Message_block_guard (MB);
/* As noted before, the Ace_message_block stores it ' s data as a
char*. We Pull and later turn it into
ace_event_handler* *
Char *c_data = Mb->base ();
/* We ' ve chosen to use a ' null ' value as a indication to leave.
If The data we got from the \ NOT NULL then we have
Some work to do. */
if (C_data)
{
/* Once again, we go to great lengths to emphasize the fact
That we ' re casting pointers around in rather impolite
Ways. We could have cast the char* directly to a
ace_event_handler* But then folks might ' s an OK
Thing to do.
(note:the correct way to use a ace_message_block is to
Write data into it. What I should have did was create a
Message blocks big enough to hold an event handler pointer
And then written the pointer value into the block. When
We got here and I would have to read so data back into a
Pointer. While politically correct, it is also a lot of
Work. If You are careful you can get away with casting
Pointers around.) */
void *v_data = (void *) C_data;
Ace_event_handler *handler = (Ace_event_handler *) V_data;
/* Now so we finally have an event handler pointer, invoke
It ' s Handle_input () method. Since we don ' t know it ' s
Handle, we just give it a default. That ' s OK because we
Know that we are not using the "handle in" method anyway. */
if (handler->handle_input (ace_invalid_handle) = =-1)
{
* Tell the handler that it's time to go home. The
Normal to shutting down a handler whose
Handler failed is to invoke Handle_close (). This would
Take care of cleaning it up for us. Notice How do we use
The handler ' s Get_handle () method to populate it ' s
"Handle" parameter.  Convenient isn ' t it? */
Handler->handle_close (Handler->get_handle (), 0);
/* Also Notice that we don ' t exit the SVC () method here!
The I did this, I was exiting. After a few
Clients disconnect you have a empty thread pool.
Hard to does any more work after that ... * *
}
}
Else
/* If We are here, we were given a message blocks with "null"
Data. This is our signal to leave and so we return (0) to
Leave gracefully. */
return 0; Ok, shutdown request
Message_block_guard goes out of scope and releases the
Message_block instance.
}
return 0;
}

Among them, the idea of management is used for two variables in the class. The Counter_guard class and the Message_block_guard class are managed separately.
Because the Ace_task class uses Ace_message_block to encapsulate messages. Therefore, the use of classes prevents memory leaks.
Ace_event_handler are event handles, similar to operators. When we deal with it, we deal with it.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.