229 lines
5.3 KiB
Plaintext
229 lines
5.3 KiB
Plaintext
note
|
|
description: "[
|
|
A thread pool manager. Manages threads up to `capacity' and queue after that,
|
|
till threads get available again.
|
|
]"
|
|
legal: "See notice at end of class."
|
|
status: "Community Preview 1.0"
|
|
date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $"
|
|
revision: "$Revision: 80577 $"
|
|
|
|
class
|
|
THREAD_POOL [G]
|
|
|
|
inherit
|
|
EXECUTION_ENVIRONMENT
|
|
|
|
create
|
|
make
|
|
|
|
feature {NONE} -- Initialization
|
|
|
|
make (n: like capacity)
|
|
-- Initialize current pool with capacity `n'.
|
|
require
|
|
n_positive: n > 0
|
|
n_not_too_large: n < {INTEGER_32}.max_value.as_natural_32
|
|
local
|
|
i: NATURAL
|
|
do
|
|
capacity := n
|
|
create work_queue.make (n.to_integer_32)
|
|
create work_queue_mutex.make
|
|
create over_mutex.make
|
|
create termination_mutex.make
|
|
create work_semaphore.make (capacity.as_integer_32)
|
|
from
|
|
i := 1
|
|
until
|
|
i > capacity
|
|
loop
|
|
work_semaphore.wait
|
|
i := i + 1
|
|
end
|
|
initialize_threads
|
|
terminated_count := capacity
|
|
is_over := False
|
|
ensure
|
|
capacity_set: capacity = n
|
|
work_queue_set: work_queue.is_empty
|
|
end
|
|
|
|
initialize_threads
|
|
-- Launches all threads
|
|
local
|
|
i: NATURAL
|
|
thread: POOLED_THREAD [G]
|
|
do
|
|
from
|
|
i := 1
|
|
until
|
|
i > capacity
|
|
loop
|
|
create thread.make (Current, work_semaphore)
|
|
thread.launch
|
|
i := i + 1
|
|
end
|
|
end
|
|
|
|
feature -- Access
|
|
|
|
capacity: NATURAL
|
|
-- Maximal number of threads allowed (queuing otherwise)
|
|
|
|
queue_count: NATURAL
|
|
-- Number of items in queue
|
|
do
|
|
work_queue_mutex.lock
|
|
Result := work_queue.count.as_natural_32
|
|
work_queue_mutex.unlock
|
|
end
|
|
|
|
feature -- Status report
|
|
|
|
valid_action (a_action: PROCEDURE): BOOLEAN
|
|
-- Is `a_action' a valid action for the current pool.
|
|
do
|
|
-- There should be no open operands.
|
|
Result := a_action.valid_operands (Void)
|
|
end
|
|
|
|
feature -- Basic operations
|
|
|
|
add_work (work: PROCEDURE)
|
|
-- Launches a thread with the specified argument `arg'. Reuse of thread if possible.
|
|
require
|
|
valid_action: valid_action (work)
|
|
do
|
|
work_queue_mutex.lock
|
|
work_queue.extend (work)
|
|
if work_queue.count <= capacity.as_integer_32 then
|
|
-- Let one thread wake up and do the work
|
|
work_semaphore.post
|
|
end
|
|
work_queue_mutex.unlock
|
|
end
|
|
|
|
over: BOOLEAN
|
|
-- Is the thread pool being terminated?
|
|
do
|
|
over_mutex.lock
|
|
Result := is_over
|
|
over_mutex.unlock
|
|
end
|
|
|
|
thread_terminated (a_thread: POOLED_THREAD [G])
|
|
-- Notifies the thread pool that a thread has terminated its execution.
|
|
do
|
|
termination_mutex.lock
|
|
terminated_count := terminated_count - 1
|
|
termination_mutex.unlock
|
|
end
|
|
|
|
get_work (requester: POOLED_THREAD [G]): detachable PROCEDURE
|
|
-- If there is work to do, it is returned
|
|
-- Yields Void otherwise
|
|
do
|
|
if not over then
|
|
work_queue_mutex.lock
|
|
if not work_queue.is_empty then
|
|
Result := work_queue.item
|
|
work_queue.remove
|
|
end
|
|
work_queue_mutex.unlock
|
|
end
|
|
end
|
|
|
|
wait_for_completion
|
|
-- Wait until there is no more work to be completed
|
|
local
|
|
done: BOOLEAN
|
|
do
|
|
from
|
|
|
|
until
|
|
done
|
|
loop
|
|
work_queue_mutex.lock
|
|
done := work_queue.is_empty
|
|
work_queue_mutex.unlock
|
|
if not done then
|
|
sleep (1)
|
|
end
|
|
end
|
|
end
|
|
|
|
terminate
|
|
-- Terminates all the threads after their execution
|
|
do
|
|
over_mutex.lock
|
|
is_over := True
|
|
over_mutex.unlock
|
|
from
|
|
termination_mutex.lock
|
|
until
|
|
terminated_count = 0
|
|
loop
|
|
work_semaphore.post
|
|
termination_mutex.unlock
|
|
termination_mutex.lock
|
|
end
|
|
termination_mutex.unlock
|
|
end
|
|
|
|
feature {NONE} -- Implementation: Access
|
|
|
|
work_queue: ARRAYED_QUEUE [PROCEDURE]
|
|
-- Queue that holds unprocessed requests as agents
|
|
-- Thread-safe access when accessor holds `queue_mutex'
|
|
|
|
work_queue_mutex: MUTEX
|
|
-- Mutex for the queue
|
|
|
|
work_semaphore: SEMAPHORE
|
|
-- Semaphore which hols the number of work to be done.
|
|
-- Needed to wake up worker threads
|
|
|
|
terminated_count: NATURAL
|
|
--
|
|
|
|
is_over: BOOLEAN
|
|
-- Is the thread pool being terminated?
|
|
|
|
over_mutex: MUTEX
|
|
-- Mutex for the `is_over' variable
|
|
|
|
termination_mutex: MUTEX
|
|
;note
|
|
copyright: "2011-2012, Javier Velilla, Jocelyn Fiat and others"
|
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
|
licensing_options: "http://www.eiffel.com/licensing"
|
|
copying: "[
|
|
This file is part of Eiffel Software's Eiffel Development Environment.
|
|
|
|
Eiffel Software's Eiffel Development Environment is free
|
|
software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published
|
|
by the Free Software Foundation, version 2 of the License
|
|
(available at the URL listed under "license" above).
|
|
|
|
Eiffel Software's Eiffel Development Environment is
|
|
distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty
|
|
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public
|
|
License along with Eiffel Software's Eiffel Development
|
|
Environment; if not, write to the Free Software Foundation,
|
|
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
]"
|
|
source: "[
|
|
Eiffel Software
|
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
|
Telephone 805-685-1006, Fax 805-685-6869
|
|
Website http://www.eiffel.com
|
|
Customer support http://support.eiffel.com
|
|
]"
|
|
end
|