Various C++ Examples (including IPC)  Version: 1.0.0
threadDeath3.cc File Reference

Thread Management Class (complex) More...

#include <iostream>
#include <stack>
#include <map>
#include <algorithm>
#include <cstring>
#include <pthread.h>
Include dependency graph for threadDeath3.cc:

Go to the source code of this file.

Classes

class  ThreadMgr
 A basic thread management class. More...
 
struct  ThreadMgr::func_arguments
 structure for static wrapper function arguments More...
 

Functions

void waitStringThreads (ThreadMgr *mgr, void **return_value)
 generic wait for string-centric threads More...
 
void * myfunc0 (void *arg)
 Example Thread function. More...
 
void * myfunc1 (void *arg)
 Example Thread function. More...
 
void * myfunc2 (void *arg)
 Example Thread function. More...
 
void * myStringFunc (void *arg)
 Example Thread function returning an object. More...
 
template<class T >
void TwaitStringThreads (ThreadMgr *mgr, T return_value)
 Example template -waits for thread and prints object. More...
 
int main (int argc, char *argv[])
 the main function More...
 

Detailed Description

Thread Management Class (complex)

Purpose:
Example class that manages threads and the detection of their exits (death) through the use of condition variables. Please see the example code and ThreadMgr class documentation for more details.

For more fundamental examples see documentation for files threadDeath1.cc and threadDeath2.cc.

The class ThreadMgr uses a map and a stack from the C++ STL to track thread IDs and their runtime status. While ThreadMgr does add some overhead to basic pthread management (in the form of some memory usage and slightly slower thread creation and destruction) the class offers a relatively easy to use interface to pthreads in general and may be enhanced for better type recognition (i.e. making it a template) and the like.

Definition in file threadDeath3.cc.

Function Documentation

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

the main function

Example 1:
A slightly overcomplicated example that attempts to cancel a thread. The thread attributes have not been set to be cancelable so milage may vary from system to system. The cancelation routine is not very robust here -this is just for demonstratio purposes to show the kinds of things we might want to do with a class implimentation like that of ThreadMgr.
Example 2:
A less complicated implimentation of Example 1. Here we don't cancel any threads.
Example 3:
Demonstrates creating a thread that both passes arguments to the user defined function as well as gets something back from the call to condWait (ultimately from pthread_join)
Note
we use a different pointer in the third example to provide a cleaner example of returning an object
 \warning an attempt to declare void **ret after example 3

yielded a consistant segmentation fault using "g++ (GCC) 3.3.3 20040125" this is considered to be a compler or linker error -I didn't bother trying to figure it out (just be aware that these things happen sometimes).

Example 4:
Demonstrates the use of two instances of the ThreadMgr class. While some of the functionality of the class uses static functions, the thread management of each instance stays with the instance. In other words, each instance of ThreadMgr manages it's own private list of threads (the threads are managed seperately).

Definition at line 448 of file threadDeath3.cc.

References ThreadMgr::cancel_thread(), ThreadMgr::condWait(), ThreadMgr::createThread(), myfunc0(), myfunc1(), myfunc2(), myStringFunc(), ThreadMgr::no_threads_terminated(), ThreadMgr::threadsActive(), TwaitStringThreads(), and waitStringThreads().

449 {
450  void **return_val;
451  void **ret;
452 
453  //string literal for later use
454  const char *pc = "987654321";
455 
456  //string object of later use (example 2)
457  std::string *str = new std::string("a string from main");
458 
459  //some thread IDs to track
460  pthread_t pret, pret2;
461 
462  //common variable
463  int i = 0;
464 
465  //the thread manager class
466  ThreadMgr m;
467 
468 
469  //##########################################################
470  std::cout << "Example 1:" << std::endl;
471  //##########################################################
472 
482  //test the functionality
483  pret = m.createThread((void *(*)(void *))myfunc0, NULL);
484  pret = m.createThread((void *(*)(void *))myfunc2, (void *)pc);
485  pret = m.createThread((void *(*)(void *))myfunc1, NULL);
486  pret2 = m.createThread((void *(*)(void *))myfunc2, (void *)pc);
487  pret = m.createThread((void *(*)(void *))myfunc1, NULL);
488  pret2 = m.createThread((void *(*)(void *))myfunc2, (void *)pc);
489  pret = m.createThread((void *(*)(void *))myfunc1, NULL);
490  pret = m.createThread((void *(*)(void *))myfunc1, NULL);
491 
492  while(m.threadsActive())
493  {
494  /*do, while there are active threads or there are threads being
495  terminated.
496  */
497 
498  //on the third itteration...
499  if(i++ == -1)
500  {
501  //cancel a thread (may lose data this way though!)
502  std::cout << "CANCELING THREAD:" << pret2 << std::endl;
503  m.cancel_thread(&pret2);
504 
505  //create another thread for fun and profit
506  pret = m.createThread((void *(*)(void *))myfunc2, (void *)pc);
507  }
508  else
509  {
510  //wait on the thread
511  m.condWait(return_val);
512  if(*return_val != NULL)
513  {
514  std::cout << "#######################main:" << ((char *)(char *)*return_val) << std::endl;
515 
516  /* This cast is not entirely proper. See the next
517  example for proper casting when deleting this pointer.
518  */
519  delete (char *)*return_val;
520  }
521  }
522  }
523 
524 
525  //##########################################################
526  std::cout << "\n" << "Example 2:" << std::endl;
527  //##########################################################
528 
534  //test the functionality
535  pret = m.createThread((void *(*)(void *))myfunc0, NULL);
536  pret = m.createThread((void *(*)(void *))myfunc2, (void *)pc);
537  pret = m.createThread((void *(*)(void *))myfunc1, NULL);
538  pret2 = m.createThread((void *(*)(void *))myfunc2, (void *)pc);
539  pret = m.createThread((void *(*)(void *))myfunc1, NULL);
540  pret2 = m.createThread((void *(*)(void *))myfunc2, (void *)pc);
541  pret = m.createThread((void *(*)(void *))myfunc1, NULL);
542  pret = m.createThread((void *(*)(void *))myfunc1, NULL);
543 
544  while(m.threadsActive())
545  {
546  /*do, while there are active threads or there are threads being
547  terminated.
548  */
549 
550  //wait on the thread
551  m.condWait(return_val);
552 
553  /* check return_val: meanwhile other threads may be dieing
554  */
555  if(*return_val != NULL)
556  {
557  /* We should get here 3 times from our usage of myfunc2
558  above */
559  std::cout << "#######################main:" << ((char *)(char *)*return_val) << std::endl;
560 
561  //delete the pointer since it was valid (not NULL)
562  delete ((char *)(char *)*return_val);
563  }
564  }
565 
566 
567  //##########################################################
568  std::cout << "\n" << "Example 3:" << std::endl;
569  //##########################################################
570 
587  //void **ret;
588 
589  //try to pass an object and get one back
590  m.createThread(myStringFunc, (void *)str);
591 
592  //while(m.threadsActive() || !m.no_threads_terminated())
593  while(m.threadsActive())
594  {
595  //wait on the thread
596  m.condWait(ret);
597  if(*ret != NULL)
598  {
599  //cast the return_val -contents of a std::string pointer
600  std::cout << *((std::string *)(std::string *)*ret) << std::endl;
601 
602  //delete the memory at the pointer
603  delete ((std::string *)(std::string *)*ret);
604  }
605 
606  }//end while()
607 
608  std::cout << "threads Active:" << m.threadsActive() << std::endl;
609  std::cout << "no_threads_terminated:" << m.no_threads_terminated() << std::endl;
610 
611  //cleanup
612  delete str;
613 
614  //##########################################################
615  std::cout << "\n" << "Example 4:" << std::endl;
616  //##########################################################
617 
626  //let's try another instance in tandum
627  ThreadMgr m1;
628 
629  //create a couple of strings
630  std::string *str1 = new std::string("string1 from main");
631  std::string *str2 = new std::string("string2 from main");
632 
633  //create a thread under m1 instance of ThreadMgr
634  m1.createThread(myStringFunc, (void *)str1);
635 
636  //create a thread under m instance of ThreadMgr
637  m.createThread(myStringFunc, (void *)str2);
638 
639 
640  //manage threads from m instance of ThreadMgr
641  waitStringThreads(&m, ret);
642 
643  //manage threads from m1 instance of ThreadMgr
644  TwaitStringThreads(&m1, (std::string **)ret);
645 
646 
647  //cleanup
648  delete str1;
649  delete str2;
650 
651  //exit normally
652  return(0);
653 }
void * myfunc2(void *arg)
Example Thread function.
void * myfunc0(void *arg)
Example Thread function.
void * myStringFunc(void *arg)
Example Thread function returning an object.
int cancel_thread(pthread_t *tid)
cancel a thread
void TwaitStringThreads(ThreadMgr *mgr, T return_value)
Example template -waits for thread and prints object.
int threadsActive()
return the number of active threads
pthread_t createThread(void *(*thread_func)(void *), void *arg)
attempt to create a new thread and register it
A basic thread management class.
Definition: threadDeath3.cc:60
bool no_threads_terminated()
answers the question "are there no theads terminated?"
void * myfunc1(void *arg)
Example Thread function.
void waitStringThreads(ThreadMgr *mgr, void **return_value)
generic wait for string-centric threads
int condWait(void **thread_return_val)
wait on a condition variable for a thread to terminate

Here is the call graph for this function:

void * myfunc0 ( void *  arg)

Example Thread function.

Simply counts and returns.

Returns
NULL is returned

Definition at line 781 of file threadDeath3.cc.

Referenced by main().

782 {
783  std::cout << "got here: myfunc0:BEGIN" << std::endl;
784 
785  for(int i=10000; i > 0; i--)
786  for(int i=10000; i > 0; i--);
787 
788  std::cout << "got here: myfunc0:END" << std::endl;
789 
790  return NULL;
791 }
void * myfunc1 ( void *  arg)

Example Thread function.

Simply counts and returns in less time than myfunc0

Returns
NULL is returned

Definition at line 798 of file threadDeath3.cc.

Referenced by main().

799 {
800  std::cout << "got here: myfunc1:BEGIN" << std::endl;
801 
802  for(int i=1000; i > 0; i--)
803  for(int i=10000; i > 0; i--);
804 
805  std::cout << "got here: myfunc1:END" << std::endl;
806 
807  return NULL;
808 }
void * myfunc2 ( void *  arg)

Example Thread function.

Purpose:
Allocate some memory and add data to the memory area. Then wait for some amount of time (in a for loop) and return a pointer to the allocated memory.
Parameters
avoid *
Returns
a char * cast to a void *
Returns
a pointer to the new memory memory area that was populated earlier

Definition at line 819 of file threadDeath3.cc.

Referenced by main().

820 {
821  std::cout << "got here: myfunc2:BEGIN" << std::endl;
822 
823  //print the value of arg from main
824  std::cout << "|arg = " << (char *)arg << std::endl;
825 
826  //create a new char and add data to the memory area
827  char *tmp = new char[10];
828  char x[10] = {"123456789"};
829 
830  //cheezy, but whatever...
831  memcpy(tmp, x, 10);
832 
833  std::cout << "myfunc2:" << tmp << std::endl;
834 
835  for(int i=10000; i > 0; i--)
836  for(int i=10000; i > 0; i--);
837 
838  std::cout << "got here: myfunc2:END" << std::endl;
839 
844  return tmp;
845 }
void * myStringFunc ( void *  arg)

Example Thread function returning an object.

Purpose:
Print the parameter from main, allocate memory and populate the new memory with data, and return a pointer to the new memory area (of type string pointer cast to a void *).
Parameters
arga void pointer
Returns
a string pointer cast to a void pointer

Definition at line 758 of file threadDeath3.cc.

Referenced by main().

759 {
760  //copy the string using casts
761  //std::string *a = ((std::string *)arg);
762  //std::cout << "myStringFunc printing:" << *a << std::endl;
763 
764  //print the contents of arg as an std::string pointer
765  std::cout << "myStringFunc printing:" << *(std::string *)arg << std::endl;
766 
767  //create a new string to be returned to the calling thread
768  std::string *s = new std::string("a string from myStringFunc");
769  std::cout << "myStringFunc returning:" << *s << std::endl;
770 
771  //cast the object as a void pointer and return
772  return ((void *)s);
773 
774  //return ((void *)NULL);
775 }
template<class T >
void TwaitStringThreads ( ThreadMgr mgr,
return_value 
)

Example template -waits for thread and prints object.

Purpose:
Example template that waits for a thread and prints out the string that is the return value from the condWait. This is here for example only and EXPECTS that the Type is something printable.
Parameters
mgrA ThreadMgr pointer
return_valueof type cast by calling function (see main for more details)
Returns
nothing
Note
a call to this function:
TwaitStringThreads(p_mgr, (string **)ret);
Yields ret to be a (string **). When we want to send it to cout then we must cast it bacwards to get the contents of the pointer of the pointer (which is a string pointer in this case). Get it?

Definition at line 723 of file threadDeath3.cc.

References ThreadMgr::condWait(), and ThreadMgr::threadsActive().

Referenced by main().

724 {
725  while(mgr->threadsActive())
726  {
727  //wait on the thread
728  mgr->condWait((void **)return_value);
729 
730  if(*return_value != NULL)
731  {
732  //cast the return_val -contents of a T pointer
733 
734  /* if we pass in a string ** then this translates to:
735  **(string **)return_value for the call to cout. remember, if
736  return_value is a pointer to an object then we want the
737  contents of the pointed to item of the pointer (it's a pointer
738  to a pointer to a pointer to something)
739  */
740  std::cout << "TwaitStringThreads:" << **((T)return_value) << std::endl;
741 
742  //delete the memory at the pointer
743  delete *return_value;
744  }
745  }//end while()
746 }
int threadsActive()
return the number of active threads
int condWait(void **thread_return_val)
wait on a condition variable for a thread to terminate

Here is the call graph for this function:

void waitStringThreads ( ThreadMgr mgr,
void **  return_value 
)

generic wait for string-centric threads

wait for a managed thread to return

Purpose:
Wait for a thread managed by the ThreadMgr pointer to return.
Parameters
mgrA ThreadMgr class pointer
return_value(must be from the function that calls createThread) This is a detail of how the staticness of the return value from the pthread_join is implimented -I think.
Note
This function could easily be made into a template. We're just doing this for now for demonstration purposes. Something along the lines of the following might do the trick:

template <class T> void waitStringThreads(ThreadMgr *mgr, T **return_value);

(Of coarse, then you would have to cast your pointer from the calling function or something like that, but that's probably not that big of a deal.)
Warning
: Due to stack undwinding, declaring the void** for the return value in this scope will simply not work. The return value pointer MUST be passed in or you will get a segmentation fault.

Definition at line 656 of file threadDeath3.cc.

References ThreadMgr::condWait(), and ThreadMgr::threadsActive().

Referenced by main().

657 {
686  //void **return_value; // doesn't work !!!!
687 
688  while(mgr->threadsActive())
689  {
690  //wait on the thread
691  mgr->condWait((void **)return_value);
692 
693  if(*return_value != NULL)
694  {
695  //cast the return_val -contents of a std::string pointer
696  std::cout << "waitStringThreads:" << *((std::string *)(std::string *)*return_value) << std::endl;
697 
698  //delete the memory at the pointer
699  delete ((std::string *)(std::string *)*return_value);
700  }
701  }//end while()
702 }
int threadsActive()
return the number of active threads
int condWait(void **thread_return_val)
wait on a condition variable for a thread to terminate

Here is the call graph for this function: