CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10

Threaded View

  1. #1
    Join Date
    Dec 2010
    Posts
    907

    A Thread that doesn't hold long enough

    I've got a process called Arrivals, this process has mean arrival time of 8 seconds.
    I've created an ExponentialStream like this,
    Code:
    #ifndef _ARRIVALS_H_
    #define _ARRIVALS_H_
    
    //#ifndef PROCESS_H_
    #  include "Process.h"
    //#endif
    
    //#ifndef RANDOM_H_
    #  include "SimuDLL\Random.h"
    //#endif
     
     
    
    class Arrivals : public Process {
    public:
        Arrivals (double);
        virtual ~Arrivals ();
    
        virtual void Body (); 
    
    private:
        ExponentialStream* InterArrivalTime;
    
    	
    };
    
    #endif
    Code:
    /*
     * Copyright (C) 1994-1998,
     *
     * Department of Computing Science,
     * The University,
     * Newcastle upon Tyne,
     * UK.
     */
    
    #ifndef ARRIVALS_H_
    #  include "Arrivals.h"
    #endif
    
    #ifndef JOB_H_
    #  include "Job.h"
    #endif
    
    #include "CMinMax.h" 
    
    
    Arrivals::Arrivals (double mean)
    		   : InterArrivalTime(new ExponentialStream(mean)) 
    {
    }
    
    Arrivals::~Arrivals () { delete InterArrivalTime; }
    
    void Arrivals::Body ()
    {
     
    	for (;;)
    	{
    		double arrivalTime = (*InterArrivalTime)();
    	
    		// Hold a number of intervals, before a new lorry arrives		 
    		Hold(arrivalTime);
    
    		CMinMax<int> lorryRand(1,3);
    		int lorryId = lorryRand.GetRandomNumber();
    
    		Job* work = new Job(lorryId);
    	
    	}
    }
    I've triggered this process in the main routine of the program
    Code:
    Sim::Sim()
    { 
    	m_Arrivals = new Arrivals(8);
    
    #ifndef NO_RESOURCE
        Resources::ref(m_Arrivals);     
    #endif
    
    	m_Arrivals->Activate();
    	m_Arrivals->Resume();
    	 
    
    	Scheduler::scheduler().Resume();
    }
    But the arrivals of different events came so fast so that I even can't identify which is which.
    (They actually came in under 0.1 s, not around 8 seconds), I conclude that the Suspend method doesn't even hold the thread. I wonder why.... I don't know this code would be where the core problem is, I will post more later.
    Thanks
    Jack


    Code:
    #ifndef __GNUG__
    static double SimulatedTime = 0.0;
    #else
    double SimulatedTime = 0.0;
    #endif
    
    #ifndef TESTQUEUE
    static Queue_Type ReadyQueue;  // Queue_Type is replaced by cpp
    #else
    Queue_Type ReadyQueue;
    #endif
    
    static Mutex* _theMutex = Mutex::create();
    
    Scheduler* Scheduler::theScheduler = (Scheduler*) 0;
    Boolean Scheduler::schedulerRunning = FALSE;
    Process* Process::Current = (Process*) 0;
    const double Process::Never = -1; // Process will never awaken.
    
    /*
     * Note: unlike in SIMULA, an active process is removed from the simulation
     * queue prior to being activated.
     */
    
    //
    // Class Scheduler
    //
    
    // scheduler is just an object, with no associated thread.
    
    Scheduler::Scheduler ()
    {
    }
    
    Scheduler::~Scheduler ()
    {
    }
    
    /*
     * This routine resets the simulation time to zero and removes all
     * entries from the scheduler queue (as their times may no longer
     * be valid). Such entries are suspended as though Cancel had been
     * called on them by a "user" process.
     *
     * Note: if this is to be used to reset the simulation environment
     * for another "run" then some means of re-initializing these queue
     * entries will be required. This is up to the user to provide and
     * invoke prior to their being used again.
     */
    
    void Scheduler::reset () const
    {
        Process* tmp = (Process*) 0;
    
        do
        {
    	tmp = ReadyQueue.Remove();
    	
    	if (tmp)
    	{
    	    tmp->Cancel();
    	    tmp->reset();  // call user-definable reset routine.
    	}
    	
        } while (tmp);
    
        SimulatedTime = 0.0;
    }
    
    double Scheduler::CurrentTime () const { return SimulatedTime; }
    
    void Scheduler::print (std::ostream& strm)
    {
        strm << "Scheduler queue:\n" << std::endl;
        
        ReadyQueue.print(strm);
    
        strm << "End of scheduler queue." << std::endl;
    }
    
    //
    // Class Process
    //
    
    /*
     * Before this process is deleted, make sure it
     * is removed from the queue, or we could have
     * problems with pointer dereferencing!
     */
    
    Process::~Process ()
    {
        /*
         * We don't call Cancel of terminate here since they will
         * attempt to suspend this process if it is running, and
         * we do not want that to occur - garbage could quickly
         * build up. So, we let the destructor run to completion
         * which will implicitly suspend the process anyway, and
         * let the thread specific destructor then decide whether
         * it needs to do anything specific (e.g., reactivate the
         * scheduler) before it finishes.
         */
    
        if (!Terminated)
        {
    	Terminated = TRUE;
    	Passivated = TRUE;
    
    	unschedule(); // remove from scheduler queue
    
    	wakeuptime = Process::Never;
    
    	if (this == Process::Current)
    	{
    	    schedule();
    	    _theMutex->unlock();
    	}
        }
    }
    
    double Process::CurrentTime () { return SimulatedTime; }
    
    void Process::set_evtime (double time)
    {
        if (!idle())  // error if we are not scheduled for activation
        {
    	if (time >= Process::CurrentTime())
    	    wakeuptime = time;
    	else
    	    error_stream << WARNING
    			 << "Process::set_evtime - time " << time
    			 << " invalid" << std::endl;
        }
        else
            error_stream << WARNING
    		     << "Process::set_evtime called for idle process." << std::endl;
    }
    
    // return process to be activated after this process.
    
    const Process* Process::next_ev () const
    {
        return ((!idle()) ? ReadyQueue.getNext(this) : (Process*) 0);
    }
    
    /*
     * These routines are slightly different to the SIMULA
     * equivalents in that a process must be given, and that
     * process must be scheduled. Complete compatibility
     * may be provided in future releases.
     */
    
    void Process::ActivateBefore (Process &p)
    {
        // No op if already scheduled
        if (Terminated || !idle()) return;
    
        Passivated = FALSE;
        if (ReadyQueue.InsertBefore(*this, p))
    	wakeuptime = p.wakeuptime;
        else
    	error_stream << WARNING << "ActivateBefore failed because 'before' process is not scheduled" << std::endl;
    }
    
    void Process::ActivateAfter (Process &p)
    {
        // No op if already scheduled
        if (Terminated || !idle()) return;
    
        Passivated = FALSE;
        if (ReadyQueue.InsertAfter(*this, p))
    	wakeuptime = p.wakeuptime;
        else
    	error_stream << WARNING << "ActivateAfter failed because 'after' process is not scheduled" << std::endl;
    }
    
    /*
     * These routines differ from their SIMULA counterparts in
     * that a negative AtTime is considered an error, and will
     * not cause the process to be activated at the current time.
     * This may change in a future release, when we may provide
     * a "SIMULA compatibility" mode.
     */
    
    void Process::ActivateAt (double AtTime, Boolean prior)
    {
        // No op if already scheduled
        if ((AtTime < Process::CurrentTime()) || Terminated || !idle()) return;
    
        Passivated = FALSE;
        wakeuptime = AtTime;
    
        ReadyQueue.Insert(*this, prior);
    }
    
    void Process::ActivateDelay (double Delay, Boolean prior)
    {
        // No op if already scheduled
        if (!checkTime(Delay) || Terminated || !idle()) return;
    
        Passivated = FALSE;
        wakeuptime = SimulatedTime + Delay;
        ReadyQueue.Insert(*this, prior);
    }
    
    void Process::Activate ()
    {
        // No op if already scheduled
        if (Terminated || !idle()) return;
    
        Passivated = FALSE;
        wakeuptime = CurrentTime();
        ReadyQueue.Insert(*this, TRUE);
    }
    
    /*
     * Similarly, there are four ways to reactivate
     * Note that if a process is already scheduled, the reactivate
     * will simply re-schedule the process.
     */
    
    void Process::ReActivateBefore (Process &p)
    {
        if (Terminated) return;
        
        unschedule();
        ActivateBefore(p);
        if (Process::Current == this)
            Suspend();
    }
    
    void Process::ReActivateAfter (Process &p)
    {
        if (Terminated) return;
        
        unschedule();
        ActivateAfter(p);
        if (Process::Current == this)
            Suspend();
    }
    
    void Process::ReActivateAt (double AtTime, Boolean prior)
    {
        if (Terminated) return;
    
        unschedule();
        ActivateAt(AtTime, prior);
        if (Process::Current == this)
            Suspend();
    }
    
    void Process::ReActivateDelay (double Delay, Boolean prior)
    {
        if (Terminated) return;
        
        unschedule();
        ActivateDelay(Delay, prior);
        if (Process::Current == this)
            Suspend();
    }
    
    void Process::ReActivate ()
    {
        if (Terminated) return;
        
        unschedule();
        Activate();
        if (Process::Current == this)
            Suspend();
    }
    
    Boolean Process::schedule ()
    {
        if (Scheduler::simulationStarted())
        {
    	Boolean doSuspend = TRUE;
        
    	Process::Current = ReadyQueue.Remove();
    
    	if (Process::Current == (Process*) 0)    // all done
    	{
    	    std::cout << "Scheduler queue is empty. Simulation ending" << std::endl;
    	    Thread::Exit();
    	}
    
    	if (Process::Current->evtime() < 0)
    	{
    	    error_stream << WARNING << "Scheduler Error: Process WakeupTime "
    			 << Process::Current->evtime() << " invalid.\n";
    	}
    	else
    	    SimulatedTime = Process::Current->evtime();
    
    #ifdef DEBUG
    	debug_stream << FUNCTIONS << FAC_SCHEDULER << VIS_PUBLIC;
    	debug_stream << "Simulated time is now " << SimulatedTime << std::endl;
    #endif
    
    	if (Process::Current != this)
    	    Process::Current->Resume();
    	else
    	    doSuspend = FALSE;
    
    	return doSuspend;
        }
        else
    	return FALSE;
    }
    
    // only called if process is running or on queue to be run
    
    void Process::unschedule ()
    {
        if (!idle())
        {
    	if (this != Process::Current)
    	    (void) ReadyQueue.Remove(this); // remove from queue
    	wakeuptime = Process::Never;
    	Passivated = TRUE;
        }
    }
    // suspend current process for simulated time t
    
    void Process::Hold (double t)
    {
        if (checkTime(t))
        {
    	if ((this == Process::Current) || (!Process::Current))
    	{
    	    wakeuptime = Process::Never;
    	    ActivateDelay(t);
    	    Suspend();
    	}
    	else
    	    error_stream << WARNING
    			 << "Process::Hold - can only be applied to active object."
    			 << std::endl;
        }
        else
    	error_stream << WARNING << "Process::Hold - time " << t
    		     << " invalid." << std::endl;
    }
    
    /*
     * We add these routines because we may need to do some
     * Process specific manipulations prior to calling the
     * thread specific implementations.
     */
    
    void Process::Suspend ()
    {
        if (schedule())
        {
    	_theMutex->unlock();
    	Thread::Suspend();
    	_theMutex->lock();
        }
    }
    Last edited by lucky6969b; July 16th, 2014 at 12:26 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured