Problem with pthreads and signaling, behavior broken...

Christopher Faylor cgf-no-personal-reply-please@cygwin.com
Tue Dec 9 04:35:00 GMT 2003


On Tue, Dec 09, 2003 at 03:01:56AM +0000, Arash Partow wrote:
>Hello Sherly,
>
>I haven't tried the ThreadTest on a solaris system however ive e-mailed
>someone that does have access to one, they will try it i'll get the results
>back to you, but out of interest what do you think the solaris system will
>do? and how do you think that behaviour will relate to cygiwn?

I must admit that I'm mystified as to what this test is trying to accomplish
but I've modified it so that it will terminate more quickly when a
signal is delivered, rather than continuing to create threads after
CTRL-C is pressed and added some more debugging output.

I've attached the modified source to this message.  I also modified the
Makefile so that it created ThreadTest.exe by default.

cgf
-------------- next part --------------
#
#  *******************************************************************
#  *                         Makefile                                *
#  * Posix Thread Test Prototype                                     *
#  *                                                                 *
#  * Author: Arash Partow                                            *
#  *                                                                 *
#  *******************************************************************
# 


MAKE             = make
CXX              = i686-pc-cygwin-g++
OPTIMIZATION_OPT = -O2
OPTIONS          = -pedantic -ansi -Wall -g $(OPTIMIZATION_OPT) -o
OPTIONS_LIBS     = -pedantic -ansi -Wall -g $(OPTIMIZATION_OPT) -c
#LIBS            = -lpthread
#LIBS            = -mthreads
LIBS             =

OBJS = 	Thread.o \
	Mutex.o \
	StringTokenizer.o

ThreadTest.exe: ThreadTestPrototype.o $(OBJS)
	$(CXX) $(OPTIONS) $@ $^ $(LIBS)

.cpp.o:
	$(CXX) $(OPTIONS_LIBS) $?
clean:
	rm -f core *.o *.bak *stackdump *.dll

-------------- next part --------------
#include "Mutex.h"

Mutex::Mutex() throw(Mutex::Exception)
{

   int result;
   
   mutex = PTHREAD_MUTEX_INITIALIZER;
   
   if ((result = pthread_mutex_init(&mutex, NULL)) != 0)
   {

      throw Exception();

   }


};


Mutex::~Mutex()
{
  
   pthread_mutex_destroy(&mutex);

};


void Mutex::lock(void) throw(Mutex::Exception)
{
	
   int result;

   tid = pthread_self();

   if ((result = pthread_mutex_lock(&mutex)) != 0)
   {

        /*
          ret could be EDEADLK
          throw Exception(something about dead lock etc...);
        */
        throw Exception();

    }

  

};


void Mutex::unlock(void) throw(Mutex::Exception)
{

  
   int result;

   tid = pthread_self();
   
   if ((result = pthread_mutex_unlock(&mutex)) != 0)
   {
     	
      throw Exception();
        
   }
 

};


void Mutex::tryLock() throw(Mutex::Exception)
{

 #ifndef _LINUX_


   if (pthread_mutex_trylock(&mutex) != 0)
   {

      throw Exception();

   }

   
 #endif  
   
};


pthread_t Mutex::getCurrent(void) const
{

   return tid;

};


pthread_mutex_t& Mutex::getMutex()
{

   return mutex;

};
-------------- next part --------------
/*
  *******************************************************************
  *                                                                 *
  * Class Name: Thread                                              *
  * Author: Arash Partow                                            *
  *                                                                 *
  *******************************************************************
*/

#ifndef INCLUDE_MUTEX_H
#define INCLUDE_MUTEX_H


#include <iostream>
#include <string.h>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "StringTokenizer.h"

#include <pthread.h>
#include <sys/types.h> 

class Mutex
{

   public:

    class Exception : public std::exception
    {
    };

    Mutex(void) throw(Exception);
   ~Mutex(void);

    void lock(void)    throw(Exception);
    void unlock(void)  throw(Exception);
    void tryLock(void) throw(Exception);


  
    pthread_t getCurrent(void) const;
    pthread_mutex_t& getMutex();
      

   private:

    pthread_mutex_t  mutex;
    pthread_t        tid;

};

#endif
-------------- next part --------------
/* 
 ****************************************************
 * Class: StringTokenizer                           *
 * By Arash Partow - 2002                           *
 * Copyright Arash Partow 2002-2003                 *
 * All Right Reserved                               *
 ****************************************************
*/

#include "StringTokenizer.h"



StringTokenizer::StringTokenizer()
{

   tokenStr   = "";
   delim      = "";

};


StringTokenizer::StringTokenizer(string str, string delim)
{

   tokenStr    = str;
   this->delim = delim;

  /*
     Remove sequential delimiter
  */

   unsigned int currentPos = 0;
   while(1==1)
   {

      if ((currentPos = tokenStr.find(delim,currentPos)) != string::npos)
      {

         currentPos +=delim.length();
         while(tokenStr.find(delim,currentPos) == currentPos)
         {

            tokenStr.erase(currentPos,delim.length());

         }

      }
      else
       break;
   }


   /*
     Trim leading delimiter
   */
   if (tokenStr.find(delim,0) == 0)
   {
      tokenStr.erase(0,delim.length());
   }

   /*
     Trim ending delimiter
   */
   if (tokenStr.rfind(delim) == (tokenStr.length()-delim.length()))
   {
      tokenStr.erase(tokenStr.length()-delim.length(),delim.length());
   }

};


StringTokenizer::~StringTokenizer()
{

   tokenStr   = "";
   delim      = "";

};


int StringTokenizer::countTokens()
{
	
   unsigned int prevPos = 0;
   int numTokens        = 0;


   if (tokenStr.length() > 0)
   {

      numTokens = 0;

      unsigned int currentPos = 0;
      while(1==1)
      {

         if ((currentPos = tokenStr.find(delim,currentPos)) != string::npos)
         {
         	
            numTokens++;
            prevPos     = currentPos;
            currentPos += delim.length();

         }
         else
          break;

      }
     
      return ++numTokens;

   }
   else
   {

      return 0;

   }

};


bool StringTokenizer::hasMoreTokens()
{

   return (tokenStr.length() > 0);

};


string StringTokenizer::nextToken()
{

   if (tokenStr.length() == 0) return "";

   string       tStr ="";
   unsigned int pos  = tokenStr.find(delim,0);

   if (pos != string::npos)
   {
   	
      tStr     = tokenStr.substr(0,pos);
      tokenStr = tokenStr.substr(pos+delim.length(),tokenStr.length()-pos);
      
   }
   else 
   {

      tStr = tokenStr.substr(0,tokenStr.length());
      tokenStr = "";
      
   } 
   
   return tStr;


};


int  StringTokenizer::nextIntToken()
{

   return atoi(nextToken().c_str());

};


double StringTokenizer::nextFloatToken()
{

   return atof(nextToken().c_str());

};


string StringTokenizer::nextToken(string delimiter)
{

   if (tokenStr.length() == 0) return "";

   string       tStr ="";
   unsigned int pos  = tokenStr.find(delimiter,0);

   if (pos != string::npos)
   {
   	
      tStr     = tokenStr.substr(0,pos);
      tokenStr = tokenStr.substr(pos+delimiter.length(),tokenStr.length()-pos);
      
   }
   else 
   {

      tStr = tokenStr.substr(0,tokenStr.length());
      tokenStr = "";
      
   } 
   
   return tStr;

};


string StringTokenizer::remainingString()
{

   return  tokenStr;

};


string StringTokenizer::filterNextToken(string filterStr)
{

   string       str        = nextToken();
   unsigned int currentPos = 0;

   while((currentPos = str.find(filterStr,currentPos)) != string::npos)
   {

      str.erase(currentPos,filterStr.length());
   }


   return str;

};
-------------- next part --------------
/* 
 ****************************************************
 * Class: StringTokenizer                           *
 * By Arash Partow - 2002                           *
 * Copyright Arash Partow 2002-2003                 *
 * All Right Reserved                               *
 ****************************************************
*/

#ifndef INCLUDE_STRINGTOKENIZER_H
#define INCLUDE_STRINGTOKENIZER_H


#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>


using namespace std;

class StringTokenizer
{
	 
   public:
   	
    StringTokenizer();
    StringTokenizer(string str, string delim);
   ~StringTokenizer();

    int    countTokens();
    bool   hasMoreTokens();
    string nextToken();
    int    nextIntToken();
    double nextFloatToken();
    string nextToken(string delim);
    string remainingString();
    string filterNextToken(string filterStr);

   private:
   
   string  tokenStr;
   string  delim;
   	
};

#endif
-------------- next part --------------
#include "Thread.h"


Thread::Thread()
{
   
   currentState = THREAD_IDLE;

};


Thread::~Thread()
{

};


bool Thread::operator==(const Thread& obj) const
{

   return (pthread_equal(threadID, obj.threadID) != 0);

};


void Thread::run()
{


   setThreadState(THREAD_RUNNING); 
   execute();
   setThreadState(THREAD_DEAD);    
   
   
};


int Thread::start()
{

   int result = 0;
 
   result = pthread_create(&threadID,NULL,&(Thread::threadFunction),this);
   
   if (result)
   {
   	
      setThreadState(THREAD_DEAD);
      cout  << "-ERROR-  CREATE FAILED  ThreadID:" << threadID << "   Result: " << result << endl;
      cout.flush();
      
   }
   else
   {
   	
      pthread_detach(threadID);
      
      
   }   
   
   return result;
   
};

void* Thread::threadFunction(void* pt)
{

   Thread* thrd = reinterpret_cast<Thread*>(pt);


   thrd->run();

   return NULL;

};



int Thread::self() const
{

   return (int)threadID;

}


void Thread::detach(void) const
{

   pthread_detach(threadID);

};


int Thread::join(void)
{

   int status = 0;
   pthread_join(threadID, (void**)&status);
   return status;

};


void Thread::terminate()
{

   pthread_cancel(threadID);

};


void Thread::exit()
{

   pthread_exit((void**)0);

};


bool Thread::setThreadState(int state)
{

   currentState = state;
   return true;

};


int Thread::getThreadState()
{

   
   return currentState;

};
-------------- next part --------------
/*
  *******************************************************************
  *                                                                 *
  * Class Name: Thread                                              *
  * Author: Arash Partow                                            *
  *                                                                 *
  *******************************************************************
*/

#ifndef INCLUDE_POSIXTHREAD_H
#define INCLUDE_POSIXTHREAD_H


#define THREAD_IDLE     0
#define THREAD_RUNNING  1
#define THREAD_DEAD     2
#define THREAD_GCR      3

#include <iostream>
#include <string.h>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "StringTokenizer.h"

#include <pthread.h>
#include <sys/types.h> 

class Thread
{
	
   public:
   
    Thread();
    virtual ~Thread();


    bool operator == (const Thread& obj) const;


    int  start();
    bool  setThreadState(int state);
    int   getThreadState();
    void  terminate();
    void  exit();


   protected:
    
    virtual void execute()=0;
    static  void* threadFunction(void *);
    void    run();
    void    detach(void) const;
    void    yield(void)  const;
    int     self()       const;
    int     join(void);
    

   
   private:
  
    pthread_attr_t attr;
    pthread_t      threadID;
    int            currentState;

};


#endif
-------------- next part --------------
/*
 ****************************************************
 * Thread-Test Prototype                            *
 * By Arash Partow                                  *
 * Copyright Arash Partow 2002-2003                 *
 * All Right Reserved                               *
 ****************************************************
*/

#include <iostream>
#include <string.h>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <windows.h>
#include "StringTokenizer.h"
#include "Thread.h"
#include "Mutex.h"


const    int MAX_THREADS = 700;
unsigned int MAX_THREAD_CREATE = 999999999;

Mutex*       printlnMutex      = NULL;


void sigproc(int sig);
string formatUInt(int val, unsigned int len);
bool println(string str);



class TestThread: public Thread
{
   public:

    TestThread(int _id):Thread()
    {
      id = _id;
    };

   ~TestThread()
    {
    };


    string reverseString(string str)
    {


       char tempch;


       /* Reverse the string */
       for(unsigned int i=0; i < (str.length()/2); i++)
       {
          tempch = str[i];
          str[i] = str[str.length()-i-1];
          str[str.length()-i-1] = tempch;

       }

       return str;

    };



    string palindrome(string str)
    {

       string tempStr = str;
       char tempch;

       /* Reverse the string */
       for(unsigned int i=0; i < (str.length()/2); i++)
       {

          tempch = str[i];
          str[i] = str[str.length()-i-1];
          str[str.length()-i-1] = tempch;

       }

       /* Produce palindrome */
       str = tempStr + str;

       return str;

    };



    void execute()
    {

       string data = "aaaa:bbbb:ccc:dddd:eee:";

       /* Build a really large string  */
       for (int i=0; i < 100; i++) data += "aaaa:bbbb:ccc:dddd:eee:";

       StringTokenizer strtok = StringTokenizer(data,":");

       /* Get each token in the string  */
       while (strtok.hasMoreTokens())
       {

          string token = strtok.nextToken();
          
          token = reverseString(token);
          token = palindrome(token);

       }
       
       println("Thread ["+formatUInt(id,7)+"] Completed.");
       
    };


  private:

   int id;

};



typedef vector <TestThread*> ThreadList;
ThreadList threadList;

class GarbageCollector: public Thread
{

   public:

    GarbageCollector()
    {

       keepRunning     = true;
       cleanupComplete = false;

    };

   ~GarbageCollector()
    {

    };


    void terminate()
    {

       keepRunning = false;

    };


    bool terminateState()
    {

       return (!keepRunning);

    };


    bool isCleanupComplete()
    {

       return cleanupComplete;

    };


    void execute()
    {


       unsigned int count = MAX_THREADS;


       while(keepRunning && (count <= MAX_THREAD_CREATE))
       {


          vector <int> delPos;

          /* Find all the current dead threads */
          for(unsigned int i=0; i < threadList.size(); i++)
          {

             if (threadList[i]->getThreadState() == THREAD_DEAD) delPos.push_back(i);

          }

          /* Recalibrate deletion positions */
          for (unsigned int i=1; i < delPos.size(); i++)
          {

             delPos[i]-=i;

          }

          for (unsigned int i=0; keepRunning && i < delPos.size(); i++)
          {

             count++;

             /* Erase thread and free-up memory */
             if(threadList[delPos[i]] != NULL) delete threadList[delPos[i]];
             threadList.erase(threadList.begin()+delPos[i]);


             /* Create a new thread to take up the just earsed thread */
             TestThread* tempThread = new TestThread(count);

             if (tempThread != NULL)
             {

                /* Add new thread to list and print out info about current thread count */
                int result = tempThread->start();
                if (result)
                {
   
                   delete tempThread;
                   
                }
                else
                {
                	
                   //cout << "Created new thread! [" << formatUInt(count,9) << "]    Result: " << result << endl;
                   println("Created new thread! ("+formatUInt(keepRunning,1)+") [" + formatUInt(count,9) + "]    Result: "+ formatUInt(result,1));
                   threadList.push_back(tempThread);
                }

             }


          }

          delPos.clear();

      }

       cout << "*********************************** thread loop terminated, keepRunning = " << keepRunning << "\n";
       cout.flush ();

      /* clean up any remaining threads */

      while(threadList.size() > 0)
      {


         vector <int> delPos;

         for(unsigned int i=0; i < threadList.size(); i++)
         {

            if (threadList[i]->getThreadState() == THREAD_DEAD) delPos.push_back(i);

         }

         /* Recalibrate deletion positions */

         for (unsigned int i=1; i < delPos.size(); i++)
         {

            delPos[i]-=i;

         }


         for (unsigned int i=0; i < delPos.size(); i++)
         {

            /* Erase thread and free-up memory */
            delete threadList[delPos[i]];
            threadList.erase(threadList.begin()+delPos[i]);

         }

         delPos.clear();


      }



      if (threadList.size() == 0) cleanupComplete = true;


   }


    bool  keepRunning;
   private:
    bool  cleanupComplete;

};




GarbageCollector* gc;

int main(int argc, char *argv[])
{

   signal(SIGINT, sigproc);
   printf ("PID %u\n", GetCurrentProcessId ());
   sleep (10);
   
   /* Create Println mutex */
   printlnMutex = new Mutex();


   /* Setup the garbage thread collector */
   gc = new GarbageCollector();

   if (argc == 2)
   {

      MAX_THREAD_CREATE = atoi(argv[1]);
      cout << "Maximum threads to be created: " << MAX_THREAD_CREATE << endl;

   }

   cout <<"Creating threads" << endl;
   sleep (2);

   /*
      create the initial MAX_THREAD threads and add
      them to the thread list
   */
   for(int i=0; gc->keepRunning && i < MAX_THREADS; i++)
   {
      TestThread* tempThread = new TestThread(i);
      threadList.push_back(tempThread);
   }


   cout <<"Starting threads" << endl;
   sleep (2);
   /*
     Have all the newly created threads start.
   */
   for(unsigned int i=0; gc->keepRunning && i < threadList.size(); i++)
   {

      threadList[i]->start();
      println("Created new thread! [" + formatUInt(i,9) + "]~");
      

   }

   cout << "Initialize garbage collector" << endl;
   cout.flush ();
   sleep (5);

   /* Initialise garbage collector */
   gc->start();


   /*
      put main thread to sleep
   */
   while(!gc->isCleanupComplete()) sleep(1);



   cout << endl << "Thread-Test has been completed." << endl;
   cout         << "Have a nice day...." << endl;

   exit(EXIT_SUCCESS);
   return 1;

}



void sigproc(int sig)
{

   signal(SIGINT, sigproc);




   if (gc != NULL)
   {

      /* Don't call terminate if already in terminate state */
      if (gc->terminateState()) return;

      cout << endl << endl << endl << endl << endl << ">>>>>>>>>>>>>>>>  Processing shutdown procedure..." << endl << endl << endl << endl << endl;
      cout.flush();
      gc->terminate();
      cout << ">>>>>>>>>>>>>>>>  Done." << endl;
   }
}


string formatUInt(int val, unsigned int len)
{

   string tempStr = "";

   char buf[100];
   sprintf(buf,"%d",val);
   tempStr =  buf;

   while(tempStr.length() < len)
   {

      tempStr = "0" + tempStr;

   }


   return tempStr;

}

bool println(string str)
{

   printlnMutex->lock();
   cout << str << endl;
   cout.flush();
   printlnMutex->unlock();
   return true;

}

-------------- next part --------------
Posix Thread Test

By Arash Partow - 2003


 1.) How to make:

 make ThreadTest


 2.) How to run:

 ./ThreadTest.exe


-------------- next part --------------
--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


More information about the Cygwin mailing list