Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Return value or Exception or something else ?

Return value or Exception or something else ?

Scheduled Pinned Locked Moved C / C++ / MFC
questioncareer
24 Posts 8 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Mr Brainley
    wrote on last edited by
    #1

    This is my function :

    CThreadPool::t_Job& CThreadPool::CJobQueue::getJob()
    {
    WaitForSingleObject(m_JobListMutex, INFINITE);

    for ( std::deque::iterator it = m\_JobList.begin(); it != m\_JobList.end(); it++ )
    	if ( it->m\_JobState != JOB\_WORKING)
    	{
    		it->m\_JobState	= JOB\_WORKING;
    		ReleaseMutex(m\_JobListMutex);
    		return (\*it);
    	}
    
    ReleaseMutex(m\_JobListMutex);
    //	Need to do something here to indicate no item has been found
    

    }

    I don't want to use a pointer for return. And i don't think it's apropriate to throw an exception, since that scenario is unavoidable, in fact quite regular. My only Idea left would be to return some special reference to a static element that functions as sort of a NULL. Any other ideas/comments ?

    W L J M Z 8 Replies Last reply
    0
    • M Mr Brainley

      This is my function :

      CThreadPool::t_Job& CThreadPool::CJobQueue::getJob()
      {
      WaitForSingleObject(m_JobListMutex, INFINITE);

      for ( std::deque::iterator it = m\_JobList.begin(); it != m\_JobList.end(); it++ )
      	if ( it->m\_JobState != JOB\_WORKING)
      	{
      		it->m\_JobState	= JOB\_WORKING;
      		ReleaseMutex(m\_JobListMutex);
      		return (\*it);
      	}
      
      ReleaseMutex(m\_JobListMutex);
      //	Need to do something here to indicate no item has been found
      

      }

      I don't want to use a pointer for return. And i don't think it's apropriate to throw an exception, since that scenario is unavoidable, in fact quite regular. My only Idea left would be to return some special reference to a static element that functions as sort of a NULL. Any other ideas/comments ?

      W Offline
      W Offline
      Waldermort
      wrote on last edited by
      #2

      why not use an enum type of predefined statuses?

      1 Reply Last reply
      0
      • M Mr Brainley

        This is my function :

        CThreadPool::t_Job& CThreadPool::CJobQueue::getJob()
        {
        WaitForSingleObject(m_JobListMutex, INFINITE);

        for ( std::deque::iterator it = m\_JobList.begin(); it != m\_JobList.end(); it++ )
        	if ( it->m\_JobState != JOB\_WORKING)
        	{
        		it->m\_JobState	= JOB\_WORKING;
        		ReleaseMutex(m\_JobListMutex);
        		return (\*it);
        	}
        
        ReleaseMutex(m\_JobListMutex);
        //	Need to do something here to indicate no item has been found
        

        }

        I don't want to use a pointer for return. And i don't think it's apropriate to throw an exception, since that scenario is unavoidable, in fact quite regular. My only Idea left would be to return some special reference to a static element that functions as sort of a NULL. Any other ideas/comments ?

        L Offline
        L Offline
        led mike
        wrote on last edited by
        #3

        Mr.Brainley wrote:

        I don't want to use a pointer for return.

        Why not? I also question why INFINITE is hard coded? Does not seem appropriate for thread pooling. Also does your pool provide a timeout mechanism to account for user code hogging and hanging threads?

        Mr.Brainley wrote:

        Any other ideas

        A smart pointer implementation that would encapsulate returning the thread to the pool etc.

        led mike

        M 1 Reply Last reply
        0
        • M Mr Brainley

          This is my function :

          CThreadPool::t_Job& CThreadPool::CJobQueue::getJob()
          {
          WaitForSingleObject(m_JobListMutex, INFINITE);

          for ( std::deque::iterator it = m\_JobList.begin(); it != m\_JobList.end(); it++ )
          	if ( it->m\_JobState != JOB\_WORKING)
          	{
          		it->m\_JobState	= JOB\_WORKING;
          		ReleaseMutex(m\_JobListMutex);
          		return (\*it);
          	}
          
          ReleaseMutex(m\_JobListMutex);
          //	Need to do something here to indicate no item has been found
          

          }

          I don't want to use a pointer for return. And i don't think it's apropriate to throw an exception, since that scenario is unavoidable, in fact quite regular. My only Idea left would be to return some special reference to a static element that functions as sort of a NULL. Any other ideas/comments ?

          J Offline
          J Offline
          Jorgen Sigvardsson
          wrote on last edited by
          #4

          Return pointer instead of reference? That way you can safely use NULL to indicate "no job". Using exceptions for that is in my opinion a complete waste of resources... May I ask why you are using mutexes? You could speed things up by using spinlocks (CRITICAL_SECTION). See docs for EnterCriticalSection(), LeaveCriticalSection(), etc, in the MSDN library. I'm assuming that the mutexes are never, or very seldom, held for a longer period of time. If they are, then mutexes is preferable, because they will put waiting thread to sleep rather than leaving it to "spin".

          -- Now with chucklelin

          M 1 Reply Last reply
          0
          • L led mike

            Mr.Brainley wrote:

            I don't want to use a pointer for return.

            Why not? I also question why INFINITE is hard coded? Does not seem appropriate for thread pooling. Also does your pool provide a timeout mechanism to account for user code hogging and hanging threads?

            Mr.Brainley wrote:

            Any other ideas

            A smart pointer implementation that would encapsulate returning the thread to the pool etc.

            led mike

            M Offline
            M Offline
            Mr Brainley
            wrote on last edited by
            #5

            I think my thread pool works different from what you think. Basically, i have a central semaphore that is increased by one each time a Job is added. On that, a thread wakes up and asks the queue for a job. The t_Job type of my example is a simple class containing a pointer to an interface with a function to execute, and state-information. The INFINITE wait here is just for the mutex on the jobqueue, wich of course needs to be synchronized. The pool does not have a timeout mechanism. I don't think it is neccessary, since i write it for a very special purpose, but anyhow i would'nt know how to implement that. Can you give me a hint there ? The main idea was, that whenever is thread is wakened by the semaphore, that means that there actually IS a job. But in Win32 you have to give a maximum count for a semaphore. Since i don't want to limit the number of jobs in my queue, i tried to find another solution, wich brought me to the problem at hand. I think i will just live with the limit (can set it high). The maximum workloud can be estimated and that will have to suffice.

            M 1 Reply Last reply
            0
            • M Mr Brainley

              This is my function :

              CThreadPool::t_Job& CThreadPool::CJobQueue::getJob()
              {
              WaitForSingleObject(m_JobListMutex, INFINITE);

              for ( std::deque::iterator it = m\_JobList.begin(); it != m\_JobList.end(); it++ )
              	if ( it->m\_JobState != JOB\_WORKING)
              	{
              		it->m\_JobState	= JOB\_WORKING;
              		ReleaseMutex(m\_JobListMutex);
              		return (\*it);
              	}
              
              ReleaseMutex(m\_JobListMutex);
              //	Need to do something here to indicate no item has been found
              

              }

              I don't want to use a pointer for return. And i don't think it's apropriate to throw an exception, since that scenario is unavoidable, in fact quite regular. My only Idea left would be to return some special reference to a static element that functions as sort of a NULL. Any other ideas/comments ?

              J Offline
              J Offline
              Jorgen Sigvardsson
              wrote on last edited by
              #6

              I see now that you are opposing the use of pointers.. why? Pointers are an intrinsic concept in C++ - why work against it? :~

              -- Presented in doublevision (where drunk)

              M 1 Reply Last reply
              0
              • M Mr Brainley

                This is my function :

                CThreadPool::t_Job& CThreadPool::CJobQueue::getJob()
                {
                WaitForSingleObject(m_JobListMutex, INFINITE);

                for ( std::deque::iterator it = m\_JobList.begin(); it != m\_JobList.end(); it++ )
                	if ( it->m\_JobState != JOB\_WORKING)
                	{
                		it->m\_JobState	= JOB\_WORKING;
                		ReleaseMutex(m\_JobListMutex);
                		return (\*it);
                	}
                
                ReleaseMutex(m\_JobListMutex);
                //	Need to do something here to indicate no item has been found
                

                }

                I don't want to use a pointer for return. And i don't think it's apropriate to throw an exception, since that scenario is unavoidable, in fact quite regular. My only Idea left would be to return some special reference to a static element that functions as sort of a NULL. Any other ideas/comments ?

                M Offline
                M Offline
                Mr Brainley
                wrote on last edited by
                #7

                Because pointers are evil. Check this FAQ for more on that topic. Also, i couldn't get it to work. Can't cast the iterator to a pointer. No idea how it can be done.

                1 Reply Last reply
                0
                • M Mr Brainley

                  I think my thread pool works different from what you think. Basically, i have a central semaphore that is increased by one each time a Job is added. On that, a thread wakes up and asks the queue for a job. The t_Job type of my example is a simple class containing a pointer to an interface with a function to execute, and state-information. The INFINITE wait here is just for the mutex on the jobqueue, wich of course needs to be synchronized. The pool does not have a timeout mechanism. I don't think it is neccessary, since i write it for a very special purpose, but anyhow i would'nt know how to implement that. Can you give me a hint there ? The main idea was, that whenever is thread is wakened by the semaphore, that means that there actually IS a job. But in Win32 you have to give a maximum count for a semaphore. Since i don't want to limit the number of jobs in my queue, i tried to find another solution, wich brought me to the problem at hand. I think i will just live with the limit (can set it high). The maximum workloud can be estimated and that will have to suffice.

                  M Offline
                  M Offline
                  Mark Salsbery
                  wrote on last edited by
                  #8

                  Have you ever used an IO completion port? It can be used for what you are doing without the semaphore release count limit. Instead of IO you would use PostQueuedCompletionStatus() to post jobs and your pool of threads wait for jobs using GetQueuedCompletionStatus(). When a waiting thread gets a completion packet it already has the job (pointer) so it doen't need to retrieve it from a list. It works pretty efficiently. Just a thought. Mark

                  M 1 Reply Last reply
                  0
                  • J Jorgen Sigvardsson

                    I see now that you are opposing the use of pointers.. why? Pointers are an intrinsic concept in C++ - why work against it? :~

                    -- Presented in doublevision (where drunk)

                    M Offline
                    M Offline
                    Mr Brainley
                    wrote on last edited by
                    #9

                    Joergen Sigvardsson wrote:

                    Pointers are an intrinsic concept in C++

                    Actually, pointers are an intrisic concept in C. C++ has references, and that has a reason. I try to follow that guideline.

                    J 1 Reply Last reply
                    0
                    • M Mark Salsbery

                      Have you ever used an IO completion port? It can be used for what you are doing without the semaphore release count limit. Instead of IO you would use PostQueuedCompletionStatus() to post jobs and your pool of threads wait for jobs using GetQueuedCompletionStatus(). When a waiting thread gets a completion packet it already has the job (pointer) so it doen't need to retrieve it from a list. It works pretty efficiently. Just a thought. Mark

                      M Offline
                      M Offline
                      Mr Brainley
                      wrote on last edited by
                      #10

                      I was not aware of such a thing. Thanks alot !

                      M 1 Reply Last reply
                      0
                      • J Jorgen Sigvardsson

                        Return pointer instead of reference? That way you can safely use NULL to indicate "no job". Using exceptions for that is in my opinion a complete waste of resources... May I ask why you are using mutexes? You could speed things up by using spinlocks (CRITICAL_SECTION). See docs for EnterCriticalSection(), LeaveCriticalSection(), etc, in the MSDN library. I'm assuming that the mutexes are never, or very seldom, held for a longer period of time. If they are, then mutexes is preferable, because they will put waiting thread to sleep rather than leaving it to "spin".

                        -- Now with chucklelin

                        M Offline
                        M Offline
                        Mr Brainley
                        wrote on last edited by
                        #11

                        Thanks for the advice on the Mutex. You are right, they are never held for long. I will change that.

                        1 Reply Last reply
                        0
                        • M Mr Brainley

                          I was not aware of such a thing. Thanks alot !

                          M Offline
                          M Offline
                          Mark Salsbery
                          wrote on last edited by
                          #12

                          Mr.Brainley wrote:

                          I was not aware of such a thing. Thanks alot !

                          No problem. I just happen to be working on some code using one right now :) There's only 3 APIs and 1 structure involved so it's pretty simple and powerful. You'll see most articles describe using them for scalable multithreaded IO but they also make a handy queue for thread pools. Cheers, Mark

                          M 1 Reply Last reply
                          0
                          • M Mr Brainley

                            Joergen Sigvardsson wrote:

                            Pointers are an intrinsic concept in C++

                            Actually, pointers are an intrisic concept in C. C++ has references, and that has a reason. I try to follow that guideline.

                            J Offline
                            J Offline
                            Jorgen Sigvardsson
                            wrote on last edited by
                            #13

                            Uhm.. that is a rather dull guideline. Just because some academic has decided that references are better than pointers (which the majority of the C++ community uses), it's counter productive NOT to use them in cases like this, as it would cut your development by at least an hour (seeing that you posted this approximately an hour ago). But hey, it's your time. :)

                            -- Based on a True Story

                            M Z 2 Replies Last reply
                            0
                            • J Jorgen Sigvardsson

                              Uhm.. that is a rather dull guideline. Just because some academic has decided that references are better than pointers (which the majority of the C++ community uses), it's counter productive NOT to use them in cases like this, as it would cut your development by at least an hour (seeing that you posted this approximately an hour ago). But hey, it's your time. :)

                              -- Based on a True Story

                              M Offline
                              M Offline
                              Mr Brainley
                              wrote on last edited by
                              #14

                              Ok, you're right. And i don't do that just because some academic decided it. I use pointers often enough. But i also take my time to explore other solutions, since i think i still have much to learn. That is why i don't just use pointers because everyone else uses them. There may be a better solution. ( and remember : The fast path leads to the dark side ;)

                              1 Reply Last reply
                              0
                              • M Mark Salsbery

                                Mr.Brainley wrote:

                                I was not aware of such a thing. Thanks alot !

                                No problem. I just happen to be working on some code using one right now :) There's only 3 APIs and 1 structure involved so it's pretty simple and powerful. You'll see most articles describe using them for scalable multithreaded IO but they also make a handy queue for thread pools. Cheers, Mark

                                M Offline
                                M Offline
                                Mr Brainley
                                wrote on last edited by
                                #15

                                actually, I'm implementing this thread pool for a scalable multithreaded IO application. Well, seems i don't need to do that anymore.

                                M 1 Reply Last reply
                                0
                                • M Mr Brainley

                                  actually, I'm implementing this thread pool for a scalable multithreaded IO application. Well, seems i don't need to do that anymore.

                                  M Offline
                                  M Offline
                                  Mark Salsbery
                                  wrote on last edited by
                                  #16

                                  Then you'll really like IO completion ports then. You can use the same pool of threads for handling queued jobs and queued IO requests if you choose to. Works slick!

                                  1 Reply Last reply
                                  0
                                  • M Mr Brainley

                                    This is my function :

                                    CThreadPool::t_Job& CThreadPool::CJobQueue::getJob()
                                    {
                                    WaitForSingleObject(m_JobListMutex, INFINITE);

                                    for ( std::deque::iterator it = m\_JobList.begin(); it != m\_JobList.end(); it++ )
                                    	if ( it->m\_JobState != JOB\_WORKING)
                                    	{
                                    		it->m\_JobState	= JOB\_WORKING;
                                    		ReleaseMutex(m\_JobListMutex);
                                    		return (\*it);
                                    	}
                                    
                                    ReleaseMutex(m\_JobListMutex);
                                    //	Need to do something here to indicate no item has been found
                                    

                                    }

                                    I don't want to use a pointer for return. And i don't think it's apropriate to throw an exception, since that scenario is unavoidable, in fact quite regular. My only Idea left would be to return some special reference to a static element that functions as sort of a NULL. Any other ideas/comments ?

                                    Z Offline
                                    Z Offline
                                    Zac Howland
                                    wrote on last edited by
                                    #17

                                    You should wrap your mutex calls in a class (open it in the constructor and release it in the destructor). This actually allows for the exception option (otherwise, throwing an exception would be bad since the code would not be exception safe). Given what you are trying to do, I would probably pass in a reference to be returned to as an argument and return a bool or some other status indicator as a return value. It would make your code look something like this:

                                    class MutexHolder
                                    {
                                    public:
                                    	MutexHolder(HANDLE mutex)
                                    	{
                                    		_Mutex = mutex;
                                    		WaitForSingleObject(_Mutex, INFINITE);
                                    		// I believe this should actually be OpenMutex
                                    		// In which case, you would change the constructor arguement to a string
                                    	}
                                    
                                    	~MutexHolder()
                                    	{
                                    		ReleaseMutex(_Mutex);
                                    	}
                                    
                                    private:
                                    	HANDLE _Mutex;
                                    };
                                    
                                    bool job_not_working(const your_deque_type& t)
                                    {
                                    	if (t.m_JobState != JOB_WORKING)
                                    	{
                                    		return true;
                                    	}
                                    }
                                    
                                    bool CThreadPool::CJobQueue::getJob(CThreadPool::t_Job& job)
                                    {
                                    	MutexHolder(m_JobListMutex);
                                    
                                    	deque<your_deque_type>::iterator it = find_if(m_JobList.begin(), m_JobList.end(), job_not_working);
                                    	if (it != m_JobList.end())
                                    	{
                                    		job = *it;
                                    		job.m_JobState = JOB_WORKING;
                                    		return true;
                                    	}
                                    	return false;
                                    }
                                    

                                    If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week Zac

                                    J 1 Reply Last reply
                                    0
                                    • Z Zac Howland

                                      You should wrap your mutex calls in a class (open it in the constructor and release it in the destructor). This actually allows for the exception option (otherwise, throwing an exception would be bad since the code would not be exception safe). Given what you are trying to do, I would probably pass in a reference to be returned to as an argument and return a bool or some other status indicator as a return value. It would make your code look something like this:

                                      class MutexHolder
                                      {
                                      public:
                                      	MutexHolder(HANDLE mutex)
                                      	{
                                      		_Mutex = mutex;
                                      		WaitForSingleObject(_Mutex, INFINITE);
                                      		// I believe this should actually be OpenMutex
                                      		// In which case, you would change the constructor arguement to a string
                                      	}
                                      
                                      	~MutexHolder()
                                      	{
                                      		ReleaseMutex(_Mutex);
                                      	}
                                      
                                      private:
                                      	HANDLE _Mutex;
                                      };
                                      
                                      bool job_not_working(const your_deque_type& t)
                                      {
                                      	if (t.m_JobState != JOB_WORKING)
                                      	{
                                      		return true;
                                      	}
                                      }
                                      
                                      bool CThreadPool::CJobQueue::getJob(CThreadPool::t_Job& job)
                                      {
                                      	MutexHolder(m_JobListMutex);
                                      
                                      	deque<your_deque_type>::iterator it = find_if(m_JobList.begin(), m_JobList.end(), job_not_working);
                                      	if (it != m_JobList.end())
                                      	{
                                      		job = *it;
                                      		job.m_JobState = JOB_WORKING;
                                      		return true;
                                      	}
                                      	return false;
                                      }
                                      

                                      If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week Zac

                                      J Offline
                                      J Offline
                                      Jorgen Sigvardsson
                                      wrote on last edited by
                                      #18

                                      The problem with that approach, is that you'd be copying the job object. That may not always be possible. If you're going to return a status value, I'd suggest the COM way of returning the job: pointer to pointer, or reference to pointer (if you're hell bent on using references)

                                      -- From the Makers of Futurama

                                      Z 1 Reply Last reply
                                      0
                                      • J Jorgen Sigvardsson

                                        The problem with that approach, is that you'd be copying the job object. That may not always be possible. If you're going to return a status value, I'd suggest the COM way of returning the job: pointer to pointer, or reference to pointer (if you're hell bent on using references)

                                        -- From the Makers of Futurama

                                        Z Offline
                                        Z Offline
                                        Zac Howland
                                        wrote on last edited by
                                        #19

                                        The object is stored in a deque, therefore it is already being copied. The only way to avoid that is to have the deque store pointers, in which case the approach still works, you just need to pass in a reference to a pointer instead.

                                        If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week Zac

                                        1 Reply Last reply
                                        0
                                        • J Jorgen Sigvardsson

                                          Uhm.. that is a rather dull guideline. Just because some academic has decided that references are better than pointers (which the majority of the C++ community uses), it's counter productive NOT to use them in cases like this, as it would cut your development by at least an hour (seeing that you posted this approximately an hour ago). But hey, it's your time. :)

                                          -- Based on a True Story

                                          Z Offline
                                          Z Offline
                                          Zac Howland
                                          wrote on last edited by
                                          #20

                                          Joergen Sigvardsson wrote:

                                          Uhm.. that is a rather dull guideline. Just because some academic has decided that references are better than pointers (which the majority of the C++ community uses), it's counter productive NOT to use them in cases like this, as it would cut your development by at least an hour (seeing that you posted this approximately an hour ago).

                                          Knowing how to use references increases code readability, maintainability, and decreases the liklihood of bugs being introduced via improper usage of pointers. In general, if you can get away with not using pointers, you should do so.

                                          If you decide to become a software engineer, you are signing up to have a 1/2" piece of silicon tell you exactly how stupid you really are for 8 hours a day, 5 days a week Zac

                                          J 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups