Boost logo

Boost :

From: Alexander Terekhov (terekhov_at_[hidden])
Date: 2001-08-04 06:56:04


> The Java specification currently allows the JVM to throw an exception
> at any time at arbitrary points in the program, for example
> asynchronously when stop is called on a Thread object. In practice it
> isn't that bad...

IT IS REALLY BAD and that is why "stop" was deprecated.
you might have a look at posix thread cancellation model
(including asynchronous cancellation which is still
possible and is designed to be safe, unless the programmer
misuse it).

regards,
alexander.

ps. fyi..

7209 B.2.9.5 Thread Cancelation
7210 Many existing threads packages have facilities for canceling an
operation or canceling a thread.
7211 These facilities are used for implementing user requests (such as the
CANCEL button in a
7212 window-based application), for implementing OR parallelism (for
example, telling the other
7213 threads to stop working once one thread has found a forced mate in a
parallel chess program), or
7214 for implementing the ABORT mechanism in Ada.
7215 POSIX programs traditionally have used the signal mechanism combined
with either longjmp()
7216 or polling to cancel operations. Many POSIX programmers have trouble
using these facilities to
7217 solve their problems efficiently in a single-threaded process. With
the introduction of threads,
7218 these solutions become even more difficult to use.
7219 The main issues with implementing a cancelation facility are
specifying the operation to be
7220 canceled, cleanly releasing any resources allocated to that operation,
controlling when the target
7221 notices that it has been canceled, and defining the interaction
between asynchronous signals and
7222 cancelation.
7223 Specifying the Operation to Cancel
7224 Consider a thread that calls through five distinct levels of program
abstraction and then, inside
7225 the lowest-level abstraction, calls a function that suspends the
thread. (An abstraction boundary
7226 is a layer at which the client of the abstraction sees only the
service being provided and can
7227 remain ignorant of the implementation. Abstractions are often layered,
each level of abstraction
7228 being a client of the lower-level abstraction and implementing a
higher-level abstraction.)
7229 Depending on the semantics of each abstraction, one could imagine
wanting to cancel only the
7230 call that causes suspension, only the bottom two levels, or the
operation being done by the entire
7231 thread. Canceling operations at a finer grain than the entire thread
is difficult because threads
7232 are active and they may be run in parallel on a multi-processor. By
the time one thread can make
7233 a request to cancel an operation, the thread performing the operation
may have completed that
7234 operation and gone on to start another operation whose cancelation is
not desired. Thread IDs
7235 are not reused until the thread has exited, and either it was created
with the Attr detachstate
7236 attribute set to PTHREAD_CREATE_DETACHED or the pthread_join () or
pthread_detach()
7237 function has been called for that thread. Consequently, a thread
cancelation will never be
7238 misdirected when the thread terminates. For these reasons, the
canceling of operations is done at
7239 the granularity of the thread. Threads are designed to be inexpensive
enough so that a separate
7240 thread may be created to perform each separately cancelable operation;
for example, each
7241 possibly long running user request.
7242 For cancelation to be used in existing code, cancelation scopes and
handlers will have to be
7243 established for code that needs to release resources upon cancelation,
so that it follows the
7244 programming discipline described in the text.
7245 A Special Signal Versus a Special Interface
7246 Two different mechanisms were considered for providing the cancelation
interfaces. The first
7247 was to provide an interface to direct signals at a thread and then to
define a special signal that
7248 had the required semantics. The other alternative was to use a special
interface that delivered the
7249 correct semantics to the target thread.
7250 The solution using signals produced a number of problems. It required
the implementation to |
7251 provide cancelation in terms of signals whereas a perfectly valid (and
possibly more efficient) |
7252 implementation could have both layered on a low-level set of
primitives. There were so many |
7253 exceptions to the special signal (it cannot be used with kill ( ), no
POSIX.1 interfaces can be used |
7254 with it) that it was clearly not a valid signal. Its semantics on
delivery were also completely |
7255 different from any existing POSIX.1 signal. As such, a special
interface that did not mandate the |
7256 implementation and did not confuse the semantics of signals and
cancelation was felt to be the |
7257 better solution.
7258 Races Between Cancelation and Resuming Execution
7259 Due to the nature of cancelation, there is generally no
synchronization between the thread
7260 requesting the cancelation of a blocked thread and events that may
cause that thread to resume
7261 execution. For this reason, and because excess serialization hurts
performance, when both an
7262 event that a thread is waiting for has occurred and a cancelation
request has been made and
7263 cancelation is enabled, IEEE Std 1003.1-200x explicitly allows the
implementation to choose
7264 between returning from the blocking call or acting on the cancelation
request.
7265 Interaction of Cancelation with Asynchronous Signals
7266 A typical use of cancelation is to acquire a lock on some resource and
to establish a cancelation
7267 cleanup handler for releasing the resource when and if the thread is
canceled.
7268 A correct and complete implementation of cancelation in the presence
of asynchronous signals
7269 requires considerable care. An implementation has to push a
cancelation cleanup handler on the
7270 cancelation cleanup stack while maintaining the integrity of the stack
data structure. If an |
7271 asynchronously-generated signal is posted to the thread during a stack
operation, the signal |
7272 handler cannot manipulate the cancelation cleanup stack. As a
consequence, asynchronous
7273 signal handlers may not cancel threads or otherwise manipulate the
cancelation state of a thread.
7274 Threads may, of course, be canceled by another thread that used a
sigwait( ) function to wait
7275 synchronously for an asynchronous signal.
7276 In order for cancelation to function correctly, it is required that
asynchronous signal handlers not
7277 change the cancelation state. This requires that some elements of
existing practice, such as using
7278 longjmp( ) to exit from an asynchronous signal handler implicitly, be
prohibited in cases where
7279 the integrity of the cancelation state of the interrupt thread cannot
be ensured.
7280 Thread Cancelation Overview
7281 · Cancelability States
7282 The three possible cancelability states (disabled, deferred, and
asynchronous) are encoded
7283 into two separate bits ((disable, enable) and (deferred,
asynchronous)) to allow them to be
7284 changed and restored independently. For instance, short code sequences
that will not block
7285 sometimes disable cancelability on entry and restore the previous
state upon exit. Likewise,
7286 long or unbounded code sequences containing no convenient explicit
cancelation points will
7287 sometimes set the cancelability type to asynchronous on entry and
restore the previous value
7288 upon exit.
7289 · Cancelation Points
7290 Cancelation points are points inside of certain functions where a
thread has to act on any
7291 pending cancelation request when cancelability is enabled, if the
function would block. As
7292 with checking for signals, operations need only check for pending
cancelation requests when
7293 the operation is about to block indefinitely.
7294 The idea was considered of allowing implementations to define whether
blocking calls such
7295 as read( ) should be cancelation points. It was decided that it would
adversely affect the
7296 design of conforming applications if blocking calls were not
cancelation points because
7297 threads could be left blocked in an uncancelable state.
7298 There are several important blocking routines that are specifically
not made cancelation
7299 points:
7300 ? pthread_mutex_lock()
7301 If pthread_mutex_lock( ) were a cancelation point, every routine that
called it would also
7302 become a cancelation point (that is, any routine that touched shared
state would
7303 automatically become a cancelation point). For example, malloc(), free
( ), and rand()
7304 would become cancelation points under this scheme. Having too many
cancelation points
7305 makes programming very difficult, leading to either much disabling and
restoring of
7306 cancelability or much difficulty in trying to arrange for reliable
cleanup at every possible
7307 place.
7308 Since pthread_mutex_lock( ) is not a cancelation point, threads could
result in being
7309 blocked uninterruptibly for long periods of time if mutexes were used
as a general
7310 synchronization mechanism. As this is normally not acceptable, mutexes
should only be
7311 used to protect resources that are held for small fixed lengths of
time where not being
7312 able to be canceled will not be a problem. Resources that need to be
held exclusively for
7313 long periods of time should be protected with condition variables.
7314 ? pthread_barrier_wait() |
7315 Canceling a barrier wait will render a barrier unusable. Similar to a
barrier timeout (which
7316 the standard developers rejected), there is no way to guarantee the
consistency of a
7317 barrier's internal data structures if a barrier wait is canceled.
7318 ? pthread_spin_lock()
7319 As with mutexes, spin locks should only be used to protect resources
that are held for
7320 small fixed lengths of time where not being cancelable will not be a
problem.
7321 Every library routine should specify whether or not it includes any
cancelation points.
7322 Typically, only those routines that may block or compute indefinitely
need to include
7323 cancelation points.
7324 Correctly coded routines only reach cancelation points after having
set up a cancelation
7325 cleanup handler to restore invariants if the thread is canceled at
that point. Being cancelable
7326 only at specified cancelation points allows programmers to keep track
of actions needed in a
7327 cancelation cleanup handler more easily. A thread should only be made
asynchronously
7328 cancelable when it is not in the process of acquiring or releasing
resources or otherwise in a
7329 state from which it would be difficult or impossible to recover.
7330 · Thread Cancelation Cleanup Handlers
7331 The cancelation cleanup handlers provide a portable mechanism, easy to
implement, for
7332 releasing resources and restoring invariants. They are easier to use
than signal handlers
7333 because they provide a stack of cancelation cleanup handlers rather
than a single handler,
7334 and because they have an argument that can be used to pass context
information to the
7335 handler.
7336 The alternative to providing these simple cancelation cleanup handlers
(whose only use is for
7337 cleaning up when a thread is canceled) is to define a general
exception package that could be
7338 used for handling and cleaning up after hardware traps and
software-detected errors. This |
7339 was too far removed from the charter of providing threads to handle
asynchrony. However,
7340 it is an explicit goal of IEEE Std 1003.1-200x to be compatible with
existing exception facilities
7341 and languages having exceptions.
7342 The interaction of this facility and other procedure-based or
language-level exception
7343 facilities is unspecified in this version of IEEE Std 1003.1-200x.
However, it is intended that it
7344 be possible for an implementation to define the relationship between
these cancelation
7345 cleanup handlers and Ada, C++, or other language-level exception
handling facilities.
7346 It was suggested that the cancelation cleanup handlers should also be
called when the
7347 process exits or calls the exec function. This was rejected partly due
to the performance
7348 problem caused by having to call the cancelation cleanup handlers of
every thread before the
7349 operation could continue. The other reason was that the only state
expected to be cleaned up
7350 by the cancelation cleanup handlers would be the intraprocess state.
Any handlers that are to
7351 clean up the interprocess state would be registered with atexit ( ).
There is the orthogonal
7352 problem that the exec functions do not honor the atexit ( ) handlers,
but resolving this is
7353 beyond the scope of IEEE Std 1003.1-200x.
7354 · Async-Cancel Safety
7355 A function is said to be async-cancel-safe if it is written in such a
way that entering the |
7356 function with asynchronous cancelability enabled will not cause any
invariants to be
7357 violated, even if a cancelation request is delivered at any arbitrary
instruction. Functions that
7358 are async-cancel-safe are often written in such a way that they need
to acquire no resources
7359 for their operation and the visible variables that they may write are
strictly limited.
7360 Any routine that gets a resource as a side-effect cannot be made
async-cancel-safe (for
7361 example, malloc( )). If such a routine were called with asynchronous
cancelability enabled, it
7362 might acquire the resource successfully, but as it was returning to
the client, it could act on a
7363 cancelation request. In such a case, the application would have no way
of knowing whether
7364 the resource was acquired or not.
7365 Indeed, because many interesting routines cannot be made
async-cancel-safe, most library
7366 routines in general are not async-cancel-safe. Every library routine
should specify whether or
7367 not it is async-cancel safe so that programmers know which routines
can be called from code
7368 that is asynchronously cancelable.

2222 2.9.5 Thread Cancelation
2223 The thread cancelation mechanism allows a thread to terminate the
execution of any other
2224 thread in the process in a controlled manner. The target thread (that
is, the one that is being
2225 canceled) is allowed to hold cancelation requests pending in a number
of ways and to perform
2226 application-specific cleanup processing when the notice of cancelation
is acted upon.
2227 Cancelation is controlled by the cancelation control functions. Each
thread maintains its own
2228 cancelability state. Cancelation may only occur at cancelation points
or when the thread is
2229 asynchronously cancelable.
2230 The thread cancelation mechanism described in this section depends
upon programs having set
2231 deferred cancelability state, which is specified as the default.
Applications shall also carefully
2232 follow static lexical scoping rules in their execution behavior. For
example, use of setjmp(),
2233 return, goto, and so on, to leave user-defined cancelation scopes
without doing the necessary
2234 scope pop operation results in undefined behavior.
2235 Use of asynchronous cancelability while holding resources which
potentially need to be released
2236 may result in resource loss. Similarly, cancelation scopes may only be
safely manipulated
2237 (pushed and popped) when the thread is in the deferred or disabled
cancelability states.
2238 2.9.5.1 Cancelability States
2239 The cancelability state of a thread determines the action taken upon
receipt of a cancelation
2240 request. The thread may control cancelation in a number of ways.
2241 Each thread maintains its own cancelability state, which may be
encoded in two bits:
2242 1. Cancelability-Enable: When cancelability is PTHREAD_CANCEL_DISABLE
(as defined in
2243 the Base Definitions volume of IEEE Std 1003.1-200x, <pthread.h>),
cancelation requests
2244 against the target thread are held pending. By default, cancelability
is set to
2245 PTHREAD_CANCEL_ENABLE (as defined in <pthread.h>).
2246 2. Cancelability Type: When cancelability is enabled and the
cancelability type is
2247 PTHREAD_CANCEL_ASYNCHRONOUS (as defined in <pthread.h>), new or
pending
2248 cancelation requests may be acted upon at any time. When cancelability
is enabled and the
2249 cancelability type is PTHREAD_CANCEL_DEFERRED (as defined in
<pthread.h>),
2250 cancelation requests are held pending until a cancelation point (see
below) is reached. If
2251 cancelability is disabled, the setting of the cancelability type has
no immediate effect as all
2252 cancelation requests are held pending; however, once cancelability is
enabled again the
2253 new type is in effect. The cancelability type is
PTHREAD_CANCEL_DEFERRED in all
2254 newly created threads including the thread in which main( ) was first
invoked.
2255 2.9.5.2 Cancelation Points
2256 Cancelation points shall occur when a thread is executing the
following functions:
2257 accept()
2258 aio_suspend()
2259 clock_nanosleep()
2260 close()
2261 connect()
2262 creat()
2263 fcntl()2
2264 fsync()
2265 getmsg()
2266 getpmsg()
2267 lockf ()
2268 mq_receive()
2269 mq_send()
2270 mq_timedreceive()
mq_timedsend()
msgrcv()
msgsnd()
msync()
nanosleep()
open()
pause()
poll ()
pread()
pthread_cond_timedwait()
pthread_cond_wait()
pthread_join ()
pthread_testcancel ()
putmsg()
putpmsg()
pwrite()
read()
readv()
recv()
recvfrom()
recvmsg()
select()
sem_timedwait()
sem_wait()
send()
sendmsg()
sendto()
sigpause()
sigsuspend()
sigtimedwait()
sigwait()
sigwaitinfo ()
sleep()
system()
tcdrain()
usleep()
wait()
waitid ()
waitpid ()
write()
writev()
2273 A cancelation point may also occur when a thread is executing the
following functions:
2274 catclose ()
2275 catgets()
2276 catopen()
2277 closedir()
2278 closelog ()
2279 ctermid()
2280 dbm_close()
2281 dbm_delete()
2282 dbm_fetch()
2283 dbm_nextkey()
2284 dbm_open()
2285 dbm_store()
2286 dlclose ()
2287 dlopen()
2288 endgrent()
2289 endhostent()
2290 endnetent()
2291 endprotoent()
2292 endpwent()
2293 endservent()
2294 endutxent()
2295 fclose ()
2296 fcntl()3
2297 fflush ()
2298 fgetc()
2299 fgetpos()
2300 fgets()
2301 fgetwc()
2302 fgetws()
2303 fopen()
2304 fprintf ()
2305 fputc()
2306 fputs()
2307 fputwc()
2308 fputws()
2309 fread()
2310 freopen()
2311 fscanf()
2312 fseek()
2313 fseeko()
2314 fsetpos()
ftell ()
ftello ()
ftw()
fwprintf()
fwrite()
fwscanf()
getc()
getc_unlocked()
getchar()
getchar_unlocked()
getcwd()
getdate()
getgrent()
getgrgid()
getgrgid_r()
getgrnam()
getgrnam_r()
gethostbyaddr()
gethostbyname()
gethostent()
gethostname()
getlogin ()
getlogin_r ()
getnetbyaddr()
getnetbyname()
getnetent()
getprotobyname()
getprotobynumber()
getprotoent()
getpwent()
getpwnam()
getpwnam_r()
getpwuid()
getpwuid_r()
gets()
getservbyname()
getservbyport()
getservent()
getutxent()
getutxid()
getutxline()
getwc()
getwchar()
getwd()
glob()
iconv_close ()
iconv_open()
ioctl ()
lseek()
mkstemp()
nftw()
opendir()
openlog()
pclose()
perror()
popen()
posix_fadvise ()
posix_fallocate()
posix_madvise()
posix_spawn()
posix_spawnp()
posix_trace_clear()
posix_trace_close()
posix_trace_create()
posix_trace_create_withlog()
posix_trace_eventtypelist_getnext_id()
posix_trace_eventtypelist_rewind()
posix_trace_flush()
posix_trace_get_attr()
posix_trace_get_filter()
posix_trace_get_status()
posix_trace_getnext_event()
posix_trace_open()
posix_trace_rewind()
posix_trace_set_filter()
posix_trace_shutdown()
posix_trace_timedgetnext_event()
posix_typed_mem_open()
printf()
pthread_rwlock_rdlock()
pthread_rwlock_timedrdlock()
pthread_rwlock_timedwrlock()
pthread_rwlock_wrlock()
putc()
putc_unlocked()
putchar()
putchar_unlocked()
puts()
pututxline()
putwc()
putwchar()
readdir()
readdir_r()
remove()
rename()
rewind()
rewinddir()
scanf()
seekdir()
semop()
setgrent()
sethostent()
setnetent()
setprotoent()
setpwent()
setservent()
setutxent()
strerror()
syslog()
tmpfile()
tmpnam()
ttyname()
ttyname_r()
ungetc()
ungetwc()
unlink()
vfprintf ()
vfwprintf()
vprintf()
vwprintf()
wprintf()
wscanf()
2315 An implementation shall not introduce cancelation points into any
other functions specified in
2316 this volume of IEEE Std 1003.1-200x.
2319 The side effects of acting upon a cancelation request while suspended
during a call of a function
2320 are the same as the side effects that may be seen in a single-threaded
program when a call to a
2321 function is interrupted by a signal and the given function returns
[EINTR]. Any such side effects
2322 occur before any cancelation cleanup handlers are called.
2323 Whenever a thread has cancelability enabled and a cancelation request
has been made with that
2324 thread as the target, and the thread then calls any function that is a
cancelation point (such as
2325 pthread_testcancel () or read( )), the cancelation request shall be
acted upon before the function
2326 returns. If a thread has cancelability enabled and a cancelation
request is made with the thread
2327 as a target while the thread is suspended at a cancelation point, the
thread shall be awakened
2328 and the cancelation request shall be acted upon. However, if the
thread is suspended at a
2329 cancelation point and the event for which it is waiting occurs before
the cancelation request is
2330 acted upon, it is unspecified whether the cancelation request is acted
upon or whether the
2331 cancelation request remains pending and the thread resumes normal
execution.
2332 2.9.5.3 Thread Cancelation Cleanup Handlers
2333 Each thread maintains a list of cancelation cleanup handlers. The
programmer uses the
2334 pthread_cleanup_push( ) and pthread_cleanup_pop( ) functions to place
routines on and remove
2335 routines from this list.
2336 When a cancelation request is acted upon, the routines in the list are
invoked one by one in LIFO
2337 sequence; that is, the last routine pushed onto the list (Last In) is
the first to be invoked (First
2338 Out). The thread invokes the cancelation cleanup handler with
cancelation disabled until the last
2339 cancelation cleanup handler returns. When the cancelation cleanup
handler for a scope is
2340 invoked, the storage for that scope remains valid. If the last
cancelation cleanup handler returns,
2341 thread execution is terminated and a status of PTHREAD_CANCELED is
made available to any
2342 threads joining with the target. The symbolic constant
PTHREAD_CANCELED expands to a
2343 constant expression of type (void *) whose value matches no pointer to
an object in memory nor
2344 the value NULL.
2345 The cancelation cleanup handlers are also invoked when the thread
calls pthread_exit().
2346 A side effect of acting upon a cancelation request while in a
condition variable wait is that the
2347 mutex is re-acquired before calling the first cancelation cleanup
handler. In addition, the thread
2348 is no longer considered to be waiting for the condition and the thread
shall not have consumed
2349 any pending condition signals on the condition.
2350 A cancelation cleanup handler cannot exit via longjmp()orsiglongjmp().
2351 2.9.5.4 Async-Cancel Safety
2352 The pthread_cancel (), pthread_setcancelstate( ), and
pthread_setcanceltype( ) functions are defined to
2353 be async-cancel safe.
2354 No other functions in this volume of IEEE Std 1003.1-200x are required
to be async-cancel-safe.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk