Why doesn't threading.join() return a value?

Chris Torek nospam at torek.net
Fri Sep 2 22:14:56 CEST 2011


>On Sep 2, 2:23 pm, Alain Ketterlin <al... at dpt-info.u-strasbg.fr>
>wrote:
>> 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.

In article <bf50c8e1-1476-41e1-b2bc-61e329bfa5be at s12g2000yqm.googlegroups.com>
Adam Skutt  <askutt at gmail.com> wrote:
>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.)

>>Re. the original question: since you can define your own Thread
>>subclass, with wathever attribute you want, I guess there was no need to
>>use join() to communicate the result. The Thread's run() can store its
>>result in an attribute, and the "client" can get it from the same
>>attribute after a successful call to join().

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
-- 
In-Real-Life: Chris Torek, Wind River Systems
Intel require I note that my opinions are not those of WRS or Intel
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W)  +1 801 277 2603
email: gmail (figure it out)      http://web.torek.net/torek/index.html



More information about the Python-list mailing list