Boost logo

Boost :

From: Alexander Terekhov (terekhov_at_[hidden])
Date: 2003-05-26 05:12:15


Alexander Terekhov wrote:
>
> "William E. Kempf" wrote:
> [...]
> > >> How about moving this discussion to c.p.t.?
> > >
> > > Well, just in case... <Forward Quoted>
> >
> > Thanks... I currently can't access c.p.t. in any reasonable manner. I'm
> > working to rectify this,
>
> http://news.cis.dfn.de might help. ;-)
>
> but in the mean time, I appreciate the cross
> > post.
>
> I'll wait a day or two and post a reply addressing some of your points
> to comp.programming.threads.

"just in case..." <Forward Inline>

Alexander Terekhov wrote:
>
> <Forward-Quoted source=Boost>
>
> "William E. Kempf" wrote:
[...]
> > >> The big hurdle for a true C++ binding is that the current state of
> > >> affairs is "good enough" for most people, and the political process of
> > >> developing a full native C++ binding would be painful. (Remember, it's
> > >> not just saying that the thread::create method takes a class member at
> > >> which the thread will start... it means reviewing every method and
> > >> template in the STL to determine which have thread safety
> > >> requirements, and deciding precisely what those requirements are and
> > >> how to meet them. Then there's the matter of cancellation points...
> > >> and so forth.)
> >
> > Most STL libraries are thread-safe today, so the analysis there wouldn't
> > be too difficult.

Well, <http://lists.boost.org/MailArchives/boost/msg47701.php>.
 
> > It just needs to be stated explicitly in the standard.
> > Cancellation points are another issue... but I don't think C++ will add
> > too many to the list already provided by POSIX.

The current C++ Std is in conflict with POSIX, to begin with. The C++
standard says that almost the entire C library doesn't throw (in effect,
everything is throw()) except just a few calls for which C++ headers
provide extern "C++" overloading to facilitate C++ callbacks. In POSIX,
a whole bunch of standard C library functions DO "throw" due to thread
cancelation. Isn't that funny?

> >
> > >> When and if the C++ standard adds true thread support, that will be,
> > >> by default and in practice, the thread binding for C++; whether the
> > >> underlying thread environment is POSIX, Win32, or something else. This
> > >> is great, as long as it doesn't do or say anything stupid, but it
> > >> still leaves a few loopholes because inevitably people will continue
> > >> to write applications that mix languages. Mixing C and C++ has never
> > >> been a problem; but if the thread model in C++ is radically different,
> > >> it could become a problem.
> >
> > Absolutely agreed. I've said all along that Boost.Threads has to be very
> > aware of what POSIX says. We can not deviate in any way from POSIX that
> > will result in conflicts between the threading systems.

Bill, Boost.Threads shall end up in standard <thread> header. But there
should also be a <cthread> standard header (it should penetrate ISO C as
well; in the form of either <pthread.h> or <cthread.h> header). Now, in
the past, I was thinking of <thread> as "just" an object layer on top of
<cthread> stuff. That was wrong. <cthread> should be fully implementable
using stuff from <thread>. I mean things along the lines of:

   typedef std::thread * pthread_t;

   extern "C" pthread_t pthread_self() throw() {
     return std::thread_self().raw_ptr();
   }

   typedef thread_specific_ptr<void, __c_TSD_cleanup> * pthread_key_t;

   extern "C" int pthread_key_create(pthread_key_t * key,
                                     void ( * dtor)(void *)) throw() {
     try {
       // can throw "shall fail" stuff only (std::bad_alloc and std::try_again)
       *key = new pthread_key_t(__c_TSD_cleanup(dtor));
       // "may fail" shall be caught in the std::unexpected() handler
     }
     catch(...) {
       return __translate_exception_to_error_code_using_throw_and_catch();
     }
     return 0;
   }

   typedef std::aligned_storage<std::mutex> pthread_mutex_t;
   typedef std::aligned_storage<std::mutexattr_t> pthread_mutexattr_t;

   extern "C" int pthread_mutex_init(pthread_mutex_t * mutex_storage,
                            const pthread_mutexattr_t * attr_storage) throw() {
     try {
       // can throw "shall fail" stuff only
       new (mutex_storage->place()) std::mutex(attr_storage->object());
       // "may fail" shall be caught in the std::unexpected() handler
     }
     catch(...) {
       return __translate_exception_to_error_code_using_throw_and_catch();
     }
     return 0;
   }

   extern "C" int pthread_mutex_destroy(pthread_mutex_t * mutex_storage) throw() {
     // destructor with implicit throw()-nothing ES
     ~mutex_storage->object();
     // "may fail" shall be caught in the std::unexpected() handler
     return 0;
   }

   #define PTHREAD_CANCELED std::thread_canceled()

   extern "C" void pthread_exit(void * ptr) throw(std::thread_termination_request) {
     (ptr == PTHREAD_CANCELED) ? std::thread_cancel() : std::thread_exit(ptr);
   }

using stuff from <thread>:

  struct thread_canceled {
    operator void * () { return &unique; }
    static thread_canceled unique;
  };

  template<typename T>
  void thread_exit(T value) {
    assert(std::thread_self().can_exit_with<T>());
    throw thread_exit_value(value);
  }

  template<>
  void thread_exit(std::thread_canceled) {
    thread_cancel();
  }

  void thread_cancel() {
    throw std::thread_cancel_request();
  }

or something like that.

> >
> > >> Furthermore, there's a missing piece that
> > >> neither POSIX 1003.1-2001 plus ISO C++ 2005 (or whatever), or even
> > >> 1003.1-2001 plus a hypothetical "1003.C++" will necessarily (or even
> > >> likely) supply -- and that's how the two interoperate.
> >
> > Agreed, but that's the case today when mixing languages. There are a lot
> > of areas which are left unspecified, even when the languages being mixed
> > are C and C++.

C and C++ WILL merge, sooner or later. The separation of C and C++
languages is/was the stupidest thing C++ authors ever did (or allowed
to happen). Well, just look what's going on with respect to GCC/G++
(adding exceptions and C-destructors IS kinda "merging", I believe).

> >
> > >> If C++ or 1003.C++ says that thread::cancel raises an exception, and
> > >> 1003.1 says that pthread_cancel() invokes cleanup handlers, does that
> > >> mean that cancelling a thread with pthread_cancel() will trigger
> > >> catch(...), or even destructors? Well, maybe not. This could more
> > >> easily be solved with a 1003.C++, perhaps, since at least the two
> > >> standards are in a family. Since the C++ standard is unlikely to
> > >> mention POSIX any more than now, it's unlikely to provide any
> > >> guarantees.
> >
> > No gaurantees. But with a C++ definition, one can at least hope that
> > implementations will try and deal with these cross-language binding issues
> > in some reasonable manner.

*You* should do it for "C subset of C++" (incompatibilities and
"restrict"-like extensions of ISO-C aside for a moment). There will
be NO problems with cross-C/C++-language bindings if Boost would come
up with some "reference implementation" (see above) of <cthread>
(i.e. also <pthread.h>) using stuff from the REAL <thread> header.

You did not seem to like to "force" windows user of Boost.Threads to
download pthreads-win32 and use Boost.Threads on top of it. YOU'RE
RIGHT! Pthreads-win32 will be shutdown as soon as you'll deliver a
<cthread> and <pthread.h> beasts implemented using stuff from the
"boosted" <thread>. And, perhaps, then even Microsoft will follow...
delivering a much better implementation of BOTH (including fully
supported cancelation for all C and C++ standard calls meant to throw
std:thread_cancel_request exception).

> > >> Perhaps that would provide an opportunity for a smaller POSIX project,
> > >> though; a PROFILE that would chink the holes where the two walls meet.
> > >> In effect, specifying a "POSIX platform" supporting both threads and
> > >> C++ that simply says "C++ cancellation is the same as POSIX
> > >> cancellation", "POSIX cleanup handlers are logically and semantically
> > >> the same as C++ object destructors", and "POSIX cancellation is
> > >> visible as a C++ exception".
> >
> > Reasonable things for POSIX to do, or at least consider, IMO.

Hardcore POSIX folks don't really "think C++", unfortunately. The only
way to get it done is to deliver POSIX threading API implementation "on
top" of Boost.Threads to them, I think. Well, this would also mean a
whole bunch of extensions to the current POSIX threading -- things like
parameterized pthread_once() and TSD destructors (to support shared_ptr
like "custom deleters" without too much overhead), etcetera.

What do you think?

regards,
alexander.


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