[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::c_plus_plus

Title:C++
Notice:Read 1.* and use keywords (e.g. SHOW KEY/FULL KIT_CXX_VAX_VMS)
Moderator:DECCXX::AMARTIN
Created:Fri Nov 06 1987
Last Modified:Thu Jun 05 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:3604
Total number of notes:18242

3561.0. "Problem with embeded PTHREAD TRY blocks and C++ destructors (cross posted from CMA conference)" by ANNECY::LAROCHE_P (Ne Suze que si l'on Sancerre) Tue May 06 1997 03:58

            <<< CLT::DISK$CLT_LIBRARY3:[NOTES$LIBRARY]CMA.NOTE;1 >>>
                           -< DECthreads Conference >-
================================================================================
Note 1539.0 Problem with embeded PTHREAD TRY blocks and C++ destructors 2 replies
ANNECY::LAROCHE_P "Ne Suze que si l'on Sancerre"     85 lines   5-MAY-1997 11:51
--------------------------------------------------------------------------------
Hello,

I have a strange behaviour with C++ objects destructors and embedded PTHREAD TRY
blocks. In some cases, the destructor associated with a given object is called 
TWICE!

This happens on the following environment:

- DIGITAL UNIX V4.0B
- DEC C++ V5.5-004

To demonstrate this, I am building and executing the following code
(build is done like that: cxx -O0 -threads -o tryTest tryTest.cxx):

--------------------------------------------------------------------------------
//
// tryTest.cxx
//

//
// Include files
//

#include <pthread.h>
#include <pthread_exception.h>
#include <iostream.h>

//
// Dummy class
//

class CDummy
{
 public:
  CDummy  () { cout << "CDummy object (" << this << ") constructor called" << endl;};
  ~CDummy () { cout << "CDummy object (" << this << ") destructor  called" << endl;};
};

void main ()
{
  TRY
  {
    //
    // Allocate automatic dummy object to demonstrate double destruction
    //

    CDummy aDummy;

    TRY
    {
      //
      // Generate PTHREAD exception
      //

      RAISE (pthread_cancel_e);
    }
    CATCH_ALL
    {
      cerr << "Inner PTHREAD exception caught" << endl;
    }
    ENDTRY
  }
  CATCH_ALL
  {
    cerr << "Outer PTHREAD exception caught" << endl;
  }
  ENDTRY
}

-------------------------------------------------------------------------------

This program outputs the following text:

CDummy object (0x11ffff100) constructor called
CDummy object (0x11ffff100) destructor  called
Inner PTHREAD exception caught
CDummy object (0x11ffff100) destructor  called

So the destructor is called twice.

Does someone have an idea on how to avoid this problem?

Thank you in advance,
Pierre

T.RTitleUserPersonal
Name
DateLines
3561.1DECC::OUELLETTEmudseason into blackfly seasonTue May 06 1997 12:402
Write a copy constructor in addition to a default constructor.
See what happens...
3561.2ANNECY::LAROCHE_PNe Suze que si l&#039;on SancerreWed May 07 1997 05:114
I added a copy constructor to my class, but nothing changed.

Thanks anyway,
Pierre
3561.3more objects than you think?HNDYMN::MCCARTHYA Quinn Martin ProductionWed May 07 1997 06:563
how many times was the copy ctor called?

bjm
3561.4Copy constructor NOT calledANNECY::LAROCHE_PNe Suze que si l&#039;on SancerreWed May 07 1997 07:0210
The copy constructor is NOT called (message couted does not appear).

For information, the copy constructor I added is:

  CDummy  (const CDummy &dummy)
  {
    cout << "CDummy object (" << this << ") copy constructor called" << endl;
  };

Pierre
3561.5DECC::OUELLETTEmudseason into blackfly seasonWed May 07 1997 13:0272
Now I see I was confused.  The pthreads thing uses setjmp to implement
C++ exception handling...  After preprocessing main looks a bit like:

void main ()
{
  __pthreadExcCtx_t __exc_ctx__;
  __exc_ctx__.__sentinel = 0x45586732;
  __exc_ctx__.__version = 2;
  pthread_exc_push_ctx_np (&__exc_ctx__);
  if (!setjmp ((__pthreadExcLong_t *)(__exc_ctx__.__jmp))) {
    CDummy aDummy;
    __pthreadExcCtx_t __exc_ctx__;
    __exc_ctx__.__sentinel = 0x45586732;
    __exc_ctx__.__version = 2;
    pthread_exc_push_ctx_np (&__exc_ctx__);
    if (!setjmp ((__pthreadExcLong_t *)(__exc_ctx__.__jmp))) {
      pthread_exc_raise_np(&(pthread_cancel_e));
    } else {
      __pthreadExceptionObj_t *PTHREAD_THIS_CATCH_NP =
        (__pthreadExceptionObj_t *)&__exc_ctx__.__cur_exception;
      __exc_ctx__.__exc_state = _PTHREAD_EXC_STATE_HANDLED;
      cerr << "Inner PTHREAD exception caught" << endl;
    }
    if ((__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_NONE) ||
        (__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_ACTIVE))
      pthread_exc_pop_ctx_np (&__exc_ctx__);
  } else {
    __pthreadExceptionObj_t *PTHREAD_THIS_CATCH_NP =
      (__pthreadExceptionObj_t *)&__exc_ctx__.__cur_exception;
    __exc_ctx__.__exc_state = _PTHREAD_EXC_STATE_HANDLED;
      cerr << "Outer PTHREAD exception caught" << endl;
  }
  if ((__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_NONE) ||
      (__exc_ctx__.__exc_state == _PTHREAD_EXC_STATE_ACTIVE))
    pthread_exc_pop_ctx_np (&__exc_ctx__);
}

Well I'm not really sure what's up, but after poking around
it appears that the flow control hidden by the setjmp has baffled
things a bit.  The problem seems to be that you've not turned off
C++ exception handling, so things may be being handled twice.
In any case compiling the program without C++ EH cleanup blocks
seems to work...

cosf> cxx cxx3561.cxx -nocleanup -lpthread
cosf> a.out
CDummy object (0x11fffef98) constructor called
Inner PTHREAD exception caught
CDummy object (0x11fffef98) destructor  called
cosf>

Perhaps there's a bug in the documentation or perhaps the driver
should use -nocleanup when -pthreads is on...

cosf> cxx cxx3561.cxx -pthread
cosf> a.out
CDummy object (0x11fffef98) constructor called
CDummy object (0x11fffef98) destructor  called
Inner PTHREAD exception caught
CDummy object (0x11fffef98) destructor  called
cosf> cxx cxx3561.cxx -pthread -nocleanup
cosf> a.out
CDummy object (0x11fffef98) constructor called
Inner PTHREAD exception caught
CDummy object (0x11fffef98) destructor  called
cosf>

I'd be inclined to call it a driver bug.
You have a workaround.  Charlie can decide what the problem is
and make an entry in our bug tracking system...  this is his week.

R.
3561.6DECC::KAOSun May 11 1997 13:5659
Since DECthread implements its own exception handling by using setjmp,
I tried to simulate the case (in .5) but failed.
My example works fine (See below).  so if you could provide some information 
about these routines (e.g. pthread_exc_push_ctx_np, pthread_exc_pop_ctx_np,
pthread_exc_raise_np, pthread_cancel_e) or their specs, we'll be happy to look
it more.

/* cpp3561b.cxx */
#include "setjmp.h"
extern jmp_buf myjmpbuf;

void raise_longjmp() {
  longjmp(myjmpbuf,0);
  return;
}

/* cpp3561a.cxx */
#include "setjmp.h"
extern "C" {extern int printf(const char *, ...);}
//
// Dummy class
//
jmp_buf myjmpbuf;
class CDummy
{
 public:
  CDummy  () { printf("CDummy constructor called. %0x\n",this);}
  ~CDummy () { printf("CDummy distructor called. %0x\n",this);}
};

extern void raise_longjmp();

void main ()
{

  if (!setjmp(myjmpbuf)) {

    CDummy aDummy;

    if (!setjmp(myjmpbuf)) {
      raise_longjmp();
    } else {
      printf("Inner PTHREAD exception caught.\n");
    }

  } else {
      printf("Outer PTHREAD exception caught.\n");
  }
}

shijun.zko.dec.com> $CEXE/deccxx_driver cpp3561a.cxx cpp3561b.cxx
cpp3561a.cxx:
cpp3561b.cxx:
shijunom> a.out
CDummy constructor called. 1fffefc0
Inner PTHREAD exception caught.
CDummy distructor called. 1fffefc0


3561.7Replied at clt::cma 1539.4DECC::KAOTue May 13 1997 14:162
This topic is discussed at clt::cma 1539.
I'll move it back to here when later becomes necessary.