Jump to content
  • Advertisement
Sign in to follow this  
phil05

C# Threads 101 question

This topic is 5010 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

For my textbased/window game, I have a command called "/sleep". This asks the player how many hours he would like to sleep, and he can enter in an amount. After each hour, it should output to the output screen (txtOutput) saying "1 hour has passed," etc. Right now, there's a long wait til it outputs anything, and when it does, it outputs more than one message. Obviously, this is because I'm running this under one thread. I need a second thread to make this work, I believe. Since I'm new to threads, I'm hoping you can tell me what I'm doing wrong here. After player types in /sleep, bHoursToSleep's boolean state is turned to true. Next, the program will notice bHoursToSleep is true, so it should do the following game state:
               // get boolean states
                if (bHoursToSleep == true)
                {
                    hours = int.Parse(sBuffer);

                    ThreadStart hoursThread = new ThreadStart(sleepingTime);
                    Thread sleepThread = new Thread(hoursThread);
                    sleepThread.Name = "Sleeping Thread";
                    sleepThread.Start();
                }

ThreadStart calls the sleepingTime() method.
        public void sleepingTime()
        {
            try
            {                
                for (int i = 0; i < hours; i++)
                {
                    AddText(i + " hour(s) pass by."); 
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }

            bHoursToSleep = false;  // turns off boolean state
        }

Error during runtime, pointing at: Application.Run(new frmMain());
Illegal cross-thread operation: Control 'txtOutput' accessed from a thread
 other than the thread it was created on.\r\nStack trace where the illegal operation occurred was:\r\n\r\n\tat System.Windows.Forms.Control.get_Handle()
\r\n\tat System.Windows.Forms.RichTextBox.ForceHandleCreate()\r\n\tat 
System.Windows.Forms.RichTextBox.get_Text()\r\n\tat 
The_Nral_Prophecies.frmMain.AddText(String)\r\n\tat The_Nral_Prophecies.frmMain.sleepingTime()\r\n\tat 
System.Threading._Thread.ThreadStart_Context(Object)\r\n\tat 
System.Threading.ExecutionContext.Run(ExecutionContext, ContextCallback, 
Object, StackCrawlMark&)\r\n\tat System.Threading._Thread.ThreadStart()\r\n\"
I tried making this clear as much as possible. Please let me know with some code examples too since I seem to better understand them. Thanks in advanced. Phil

Share this post


Link to post
Share on other sites
Advertisement
Phil, there are times for threads and there are times not for threads. This is a time not for threads. (hope your going well, btw).

If you have controll over the game clock, then maybe something like


gameclock += houramount

print "Sleeping..."
for x = 0 to houramount
print "Slept for " x " hours"
wait(100)
next x


Maybe?

Also, try not to do this with your parsing.

Entered "\sleep"

You do and uppercase it to "\SLEEP", you can then do a function pointer (or similar, there are functions like "callbyname" which work fine in vb6) and call the sleep function, with the rest of the paramiters (freshly parsed, by a different function).

You do not go

Entered "\sleep"

Go and set up bool flags, and a whole lot of other stuff
Check bool flags, and do something

It will just make things harder later on in the project.

From,
Nice coder

Share this post


Link to post
Share on other sites
Quote:
Original post by Nice Coder

gameclock += houramount

print "Sleeping..."
for x = 0 to houramount
print "Slept for " x " hours"
wait(100)
next x

I wouldn't recommend doing this, it prevents you from doing anything else during the wait() call (at least, nothing in the current thread).

Share this post


Link to post
Share on other sites
I think I see what you're saying. I rearranged my code to this...


// get boolean states
if (bHoursToSleep == true)
{
try
{
int hours = int.Parse(sBuffer);

for (int i = 0; i < hours; i++)
{
AddText(i + " hour(s) pass by.");
Thread.Sleep(300);
}

bHoursToSleep = false;

}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}




However, using the for(;;) is causing the program to wait til its fully done until it outputs anything to the screen. That's why I thought threads would prevent that from happening, and print each one out individually. Please note that this is in Windows and not in console. I have no problem doing this in the console, but it seems like it's different for Windows. Please let me know, and thanks joanusdmentia for the link.

Share this post


Link to post
Share on other sites
Currently, everything freezes when I start the sleep command. Here's my code once again..


// get boolean states
if (bHoursToSleep == true)
{

try
{
hours = int.Parse(sBuffer);

System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 5 seconds.
aTimer.Interval = 1000;
aTimer.Enabled = true;

while (i != hours) ;


bHoursToSleep = false;

}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}




public void OnTimedEvent(object source, ElapsedEventArgs e)
{
AddText(i + " hour(s) pass by.");
i++;

}



[Edited by - phil05 on March 3, 2005 5:19:57 AM]

Share this post


Link to post
Share on other sites
You don't want that while() statement in your Sleep() function, you're preventing the windows message loop from executing so nothing will get updated.

First, a class that handles sleeping

class SleepTimer
{
private event EventHandler hourElapsed;
private event EventHandler finishedSleeping;

private int hoursToSleep;
private int hoursPassed;

private System.Timers.Timer timer;

public SleepTimer()
{
timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer.Interval = 1000;
}

public void StartSleeping(int hours)
{
hoursToSleep = hours;
hoursPassed = 0;
timer.Enabled = true;
}

public boolean IsSleeping
{
get { return hoursPassed<hoursToSleep; }
}

public event EventHandler HourElapsed
{
add { hourElapsed += value; }
remove { hourElapsed -= value; }
}

public event EventHandler FinishedSleeping
{
add { finishedSleeping += value; }
remove { finishedSleeping -= value; }
}

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
if(hourElapsed!=null) hourElapsed();
if (++hoursPassed == hoursToSleep) {
timer.Enabled = false;
if(finishedSleeping!=null) finishedSleeping();
}
}
}





You would set the sleep timer up at initialisation

sleepTimer = new SleepTimer();
sleepTimer.HourElapsed += new EventHandler(HourElapsedHandler);
sleepTimer.FinishSleeping += new EventHandler(FinishSleepingHandler);





And to start sleeping, it's a one-liner

sleepTimer.StartSleeping(hours);





Finally, in your game loop just check if we're sleeping

while(!quit)
{
// Run the windows message loop
Application.DoEvents();

// Update stuff here
//...

// Only handle user input if we aren't sleeping
if(!sleepTimer.Sleeping)
HandlerUserInput();
}





[Edited by - joanusdmentia on March 3, 2005 2:25:44 PM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!