Menu

Illegal instruction?

Help
Anonymous
2000-03-18
2000-03-23
  • Anonymous

    Anonymous - 2000-03-18

    Hi!

    I'm working on a small C++ project of mine and I'm looking into using Common C++ as a threading library. However, when I made some test programs for the Thread class I got some strange behaviour.

    More specifically, when I derive a class from Thread and put a "delete this" in Final(), I get "Illegal instruction" when the object tries to delete itself. However, I don't get this behaviour if I derive my class from more than one superclass, with Thread being the second one. I can include a sample program if needed.

    Since I'm new to C++, I haven't been able to dig deeper into it. Basically, what I'm wondering is this is an actual bug, or if it's an undesirable behaviour which is local to my system, or if I've simply not figured how to use the classes.

    Thanks!

    Oh, and one second thing; is there a way to wait for a thread to finish executing other than using a Semaphore or Mutex?

    /Daniel

     
    • David Sugar

      David Sugar - 2000-03-18

      If you delete a thread from another thread, as in:

      new thread mythread(...)
      ...
      delete thread;

      The "delete" will not complete until the other thread terminates.  Delete actually performs a "join" and waits on the other thread to complete.  Depending on how setCancel() was set, the other thread may either immediately terminate, may terminate at a "cancellation point", or may ignore the request.  In any case, the thread requesting the delete will not continue until the other thread terminates.  Hence, no implicit mutex or semaphore is needed to synchronize a delete.

      In regards to using "delete this" in final, I have had different opinions on this from different people.  Generally it's a bad idea if there is a possibility that your object may be created as an "automatic" variable rather than through new, and hence the default was not to do this as it will crash the image (segfault, illegal instruction, or just odd behavior), and I gather this is what you have done.  However, if you do only use "new" to create your thread objects, it should be completely safe to have them self-delete, and the tcpthread example now uses this behavior.

       
      • Anonymous

        Anonymous - 2000-03-18

        Thanks for the help!

        In this case, I wasn't using an object allocated on the stack, which is why it surprised me in the first place. I actually stripped bare the tcpthread example before I found the reason why my own example freaked out; tcpthread derives its thread-class from a Semaphore and a Thread, whereas my freaky example just derives from Thread, which is when the problem arises.

        Here's a code snippet which (on my system) produces 'Illegal instruction' when running Final():

        #include <iostream.h>
        #include <cc++/thread.h>

        class ThreadTest : public Thread
        {
        private:
          void Run() { cout << "Run()..." << endl; };
          void Final() { cout << "Final()..." << endl; delete this; };
        };

        int main()
        {
          ThreadTest * thread = new ThreadTest;
          thread->Start();
          ccxx_sleep(250);
        }

        The output looks like this:

        <tjost@sane>$ c++ -D_REENTRANT -lccxx -lpthread -othtest thtest.cxx
        <tjost@sane>$ ./thtest
        Run()...
        Final()...
        Illegal instruction
        <tjost@sane>$

        I've tried pretty much everything I could think of to see if it would help; using different compilation options, fiddling with the declaration/definition of the class and methods, creating it from another thread, and so on. Nothing except deriving ThreadTest from two classes has worked, where Thread is the /second/ class being derived from. Like this:

        class ThreadTest : public Semaphore, public Thread { ... };

        It's not really a big issue, cause I don't plan to do much self-deleting anyway; I'm just mainly curious to find out where the problem lies. If there is one in the first place...

        /Daniel

         
        • David Sugar

          David Sugar - 2000-03-18

          I like this because it's a very simple test case.  The only reason tcpthread was compounded with a semaphore was to have it hold itself as it's own starting semaphore.

          While semaphores are uneeded for delete or destructors, they are required for starting a thread, at least if the pthread_create call occurs in the constructor.  This is because if pthread_create is performed in the constructor, none of the virtual methods (including Run() are nessisarly functional; some compilers will create an object with a virtual table at constructor start, some will not complete the virtual table to derived classes until the constructor itself terminates.

          Using a starting semaphore simply blocks the thread until after the constructor exits, and using itself is simply a convenience.  If one does not specify a starting semaphore then the "start()" call can pass one.  However, if no starting semaphore is used, then the thread_create actually occurs during Start() rather than in the constructor.

          I do not see why this would make any difference in the behavior of your final method, but this better explains how and why your test case does differs from the tcpthread example.

           
          • Anonymous

            Anonymous - 2000-03-19

            Yes, that makes sense.

            I take it you don't get the same behaviour as I do when running my test case?

            /Daniel

             
            • David Sugar

              David Sugar - 2000-03-20

              I simply haven't had a chance to look at it properly yet.  I am going to add your test case to the demo directory, and expairement with it there.  At the moment I am finishing the new serial I/O classes.

               
            • David Sugar

              David Sugar - 2000-03-20

              It seems in thread.cpp, Final() is invoked too early.  It should actually
              appear as the last method call before the pthread_exit() since the
              remaining operations still must reference the thread object.  Moving
              it to before pthread_exit() also gaurentees that Final is ran after
              the thread has been detached, though this also means the final
              method is technically ran AFTER the parent notify occurs.

               
              • Anonymous

                Anonymous - 2000-03-23

                Oh, neat!

                I'll go get the latest version and start playing around with it right away.  :)

                Thanks!

                /Daniel

                 

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.