Sorry, you're wrong, at least for POSIX threads:
void pthread_exit(void *value_ptr);
int pthread_join(pthread_t thread, void **value_ptr);
pthread_exit can pass anything, and that value will be retrieved with
pthread_join.
[/QUOTE]
No, it can only pass a void*, which isn't much better than passing an
int.
It is far better than passing an int, although it leaves you with
an annoying storage-management issue, and sidesteps any reasonable
attempts at type-checking (both of which are of course "par for
the course" in C). For instance:
struct some_big_value {
... lots of stuff ...
};
struct some_big_value storage_management_problem[SIZE];
...
void *func(void *initial_args) {
...
#ifdef ONE_WAY_TO_DO_IT
pthread_exit(&storage_management_problem[index]);
/* NOTREACHED */
#else /* the other way */
return &storage_management_problem[index];
#endif
}
...
int error;
pthread_t threadinfo;
pthread_attr_t attr;
...
pthread_attr_init(&attr);
/* set attributes if desired */
error = pthread_create(&threadinfo, &attr, func, &args_to_func);
if (error) {
... handle error ...
} else {
...
void *rv;
result = pthread_join(&threadinfo, &rv);
if (rv == PTHREAD_CANCELED) {
... the thread was canceled ...
} else {
struct some_big_value *ret = rv;
... work with ret->field ...
}
}
(Or, do dynamic allocation, and have a struct with a distinguishing
ID followed by a union of multiple possible values, or a flexible
array member, or whatever. This means you can pass any arbitrary
data structure back, provided you can manage the storage somehow.)
Passing a void* is not equivalent to passing anything, not even
in C. Moreover, specific values are still reserved, like
PTHREAD_CANCELLED.
Some manual pages are clearer about this than others. Here is one
that I think is not bad:
The symbolic constant PTHREAD_CANCELED expands to a constant
expression of type (void *), whose value matches no pointer to
an object in memory nor the value NULL.
So, provided you use pthread_exit() "correctly" (always pass either
NULL or the address of some actual object in memory), the special
reserved value is different from all of "your" values.
(POSIX threads are certainly klunky, but not all *that* badly designed
given the constraints.)
For that matter, you can use the following to get what the OP asked
for. (Change all the instance variables to __-prefixed versions
if you want them to be Mostly Private.)
import threading
class ValThread(threading.Thread):
"like threading.Thread, but the target function's return val is captured"
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, verbose=None):
super(ValThread, self).__init__(group, None, name, None, None, verbose)
self.value = None
self.target = target
self.args = args
self.kwargs = {} if kwargs is None else kwargs
def run(self):
"run the thread"
if self.target:
self.value = self.target(*self.args, **self.kwargs)
def join(self, timeout = None):
"join, then return value set by target function"
super(ValThread, self).join(timeout)
return self.value