I'm in the process of writing a simple "Score Attack" Poker game. A player assembles poker hands which are worth points as a timer ticks down. My problem is a game over scenario.
My game logic runs in a single thread since the game itself is so simple. I need to know how to terminate that thread as it is, with the player no longer able to make input. I've read on the MSDN that the safe way to do this is to use a loop to cause the thread's method to return and end the thread. The problem I run into is that my game requires user input, and the user input would cause the loop to not be checked at the moment the timer ticks to zero.
The code so far uses the Thread.Abort(), and it works, but from my searching on this site that is universally regarded as a bad idea. Is there any way I could set a condition that would terminate the thread safely regardless of methods within said thread needing input? (Console.ReadLine())
Code for the game loop and timer callback that aborts the thread:
private void GameLoop()
{
double stash = 0;
while (true)
{
player.SwapCards(gameDeck);
Table.WriteInfo("Stash This Hand? y/n");
if (Console.ReadLine().Equals("y"))
{
countdown += (int)ScoreHand(player.Hand);
stash += ScoreHand(player.Hand);
BankHand();
}
}
}
private void TimeDrop(object state)
{
countdown--;
Debug.WriteLine(countdown);
if (countdown == 0)
{
GameThread.Abort();
GameOverThread.Start();
Timer.Dispose();
}
}
As it sits the loop simply runs until the thread is aborted.
Edit:
Upon request, the code the starts the threads:
public Game()
{
gameDeck = new Deck();
InitPlayer();
DealHand();
countdown = 60;
GameThread = new Thread(GameLoop);
GameOverThread = new Thread(GameOver);
Timer = new Timer(new TimerCallback(TimeDrop), null, 0, 1000);
Timer.Change(0, 1000); //Ensures timer won't be garbage collected
GameThread.Start();
}
This sort of thing can be implemented easier and cleaner using async/await rather than threads.
First we need to wrap the blocking console input method with one that is cancellable (and async). The method polls the console using KeyAvailable and asynchronously delaying while checking the CancellationToken.
public static async Task<ConsoleKeyInfo> ReadKeyAsync(CancellationToken cancellationToken)
{
while (!Console.KeyAvailable)
{
await Task.Delay(100, cancellationToken);
}
return Console.ReadKey();
}
Now we can start this async method and pass a cancellation token from a CancellationTokenSource that will automatically cancel after a specific amount of time (10 seconds as an example).
public static async Task Main(string[] args)
{
Console.WriteLine("You have 10 seconds to press the Y key...");
var cts = new CancellationTokenSource(10_000);
try
{
while (true)
{
var key = await ReadKeyAsync(cts.Token);
if (key.Key == ConsoleKey.Y)
{
Console.WriteLine("Good job!");
break;
}
else
{
Console.WriteLine("Wrong Key");
}
}
}
catch (OperationCanceledException)
{
Console.Write("Time up!");
}
}
Related
Task description:
Write a program that reads an positive integer value n (n > 3), then
creates n threads (each thread has id; id starts from 1) and works
until it receives a stop signal. All of n threads are waiting for a
signal. Every second main thread sends a signal for a random thread,
then that thread should print its id and return to a waiting state.
Requirements:
All additional threads should be finished correctly. At the thread
function exit, a message about exit should be printed. While the
thread is waiting for the condition variable, spurious wakeup should
be checked. Only std::cout allowed for text output. Stop signal is
SIGINT (ctrl+c).
I have written the following code for the above question but in output, all the threads are not exiting. I am not able to figure out the problem as I am new to this topic. Any kind of help will be really appreciated.
class Program
{
public static void Main()
{
var numberofthreads = Convert.ToInt32(Console.ReadLine());
ProcessingClass myobject = new ProcessingClass();
myobject.createThreads(numberofthreads);
}
}
public class ProcessingClass
{
public Mutex mymutex = new Mutex();
private bool thread_flag = false;
public void createThreads(int numberofthreads)
{
var threads = new List<Thread>(numberofthreads);
for (int i = 0; i < numberofthreads; i++)
{
Thread th = new Thread(() =>
{
threadsworking();
});
th.Name = "Thread" + i;
th.Start(); // <-- .Start() makes the thread start running
threads.Add(th);
}
Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs e) =>
{
var isCtrlC = e.SpecialKey == ConsoleSpecialKey.ControlC;
if (isCtrlC)
{
thread_flag = true;
int num = 1;
foreach (var thread in threads)
{
thread.Join();
Console.WriteLine($"Thread {num} exits");
num++;
}
}
e.Cancel = true;
};
}
public void threadsworking()
{
while (thread_flag == false)
{
mymutex.WaitOne(); // Wait until it is safe to enter.
Console.WriteLine("{0}", Thread.CurrentThread.Name);
Thread.Sleep(1000); // Wait until it is safe to enter.
mymutex.ReleaseMutex(); // Release the Mutex.
}
}
}
enter image description here
Consider preventing mutex from blocking threads from exiting.
When you use mutex.WaitOne() it blocks execution until the Mutex is owned by that thread. This can be really helpful for ensuring a thread has exclusive control over a shared resource. However, where this becomes a problem is when you want to arbitrarily end those threads such as when you invoke the event on the Console.CancelKeyPress.
You can see the effects of this by logging before and after the thread.Join() call you do in the event.
thread_flag = true;
int num = 1;
foreach (var thread in threads)
{
Console.WriteLine($"Joining {thread.Name}");
thread.Join();
Console.WriteLine($"Joined {thread.Name}");
Console.WriteLine($"Thread {num} exits");
num++;
}
When we do that logging it will show us that when you call Join() on Thread # 1 you see Joining 1. Then there is a really long pause, other threads still are doing work, and then finally all the threads join back to back.
The reason for this is - while Join() is waiting for Thread 1 to finish, Thread 1 is still waiting for the mutex.
Even though you set the thread_flag flag to true, Thread 1 can't exit because it hasn't taken ownership of the mutex to perform it's work and eventually exit the while() loop.
We can solve this issue fairly simply.
Consider using a timeout when waiting for the mutex
When you call .WaitOne(n) on the mutex you can wait for n given milliseconds and give up taking ownership of the mutex.
This will allow more frequent evaluations of the while loop, and subsequently more times that the threadsworking method checks to see if it should exit(using the thread_flag flag).
Heres a short example how implementing that change might look
public void threadsworking()
{
while (thread_flag == false)
{
// wait to enter the mutex, give timeout to prevent blocking
// until mutex opens and use the bool returned to determine
// if we should release the mutex or not
if (mymutex.WaitOne(1))
{
try
{
Console.WriteLine("{0}", Thread.CurrentThread.Name);
Thread.Sleep(1000); // Wait until it is safe to enter.
}
finally
{
// make sure even if we encounter an error the mutex is released
mymutex.ReleaseMutex(); // Release the Mutex.
}
}
// allow other threads to continue their work instead of blocking with a while loop, this is optional depending on the workload
Thread.Yield();
}
}
I found this
Run async method regularly with specified interval
which does half of what I want, but at the same time I want to be able to stop the loop whenever I want and then resume it as well. However while it's stopped, I don't want the infinite loop to keep running where the body gets skipped through a flag.
Basically I don't want this
while (true) {
if (!paused) {
// run work
}
// task delay
}
because then the while loop still runs.
How can I set it so that while its paused, nothing executes?
How can I set it so that while its paused, nothing executes?
That's hard to answer: if you define "pause" as: the object state remains valid while the loop doesn't use any resources then you'll have to stop and restart it (the loop).
All other timers, including Thread.Sleep, Task.Delays etc. will put your thread in idle/suspended mode.
If that's not sufficient for your needs, you'll need to actually stop the "infinite" loop.
It will free up thread related resources as well.
More info about sleep:
Thread.Sleep
More about sleep
You could use System.Threading.Timer and dispose of it while it is not in use and re-create it when you are ready to "resume". These timers are light weight so creating and destroying them on demand is not a problem.
private System.Threading.Timer _timer;
public void StartResumeTimer()
{
if(_timer == null)
_timer = new System.Threading.Timer(async (e) => await DoWorkAsync(e), null, 0, 5000);
}
public void StopPauseTimer()
{
_timer?.Dispose();
_timer = null;
}
public async Task DoWorkAsync(object state)
{
await Task.Delay(500); // do some work here, Task.Delay is just something to make the code compile
}
If you are really adverse to timers and want it to look like a while loop, then you can use TaskCompletionSource<T>:
private TaskCompletionSource<bool> _paused = null;
public async Task DoWork()
{
while (true)
{
if (_paused != null)
{
await _paused.Task;
_paused = null;
}
//run work
await Task.Delay(100);
}
}
public void Pause()
{
_paused = _paused ?? new TaskCompletionSource<bool>();
}
public void UnPause()
{
_paused?.SetResult(true);
}
I want to create a program that makes keyboard event for every 10 seconds.
but once my code starts to perform,
it can't stop until it's finished.
Is there any way to stop to close the program??
Can I make it detect my keyboard action by two seconds, like detect hitting ESC to stop the program?
My code is at below.
private void StartAction()
{
int minutes = 2;
Process pr = Process.Start("notepad.exe");
for (int a = 0; a < minutes; a++)
{
for (int b = 0; b < 6; b++)
{
Thread.Sleep(2000);
Thread.Sleep(2000);
Thread.Sleep(2000);
Thread.Sleep(2000);
Thread.Sleep(2000);
SendKeys.Send("KeyBoard Action");
}
}
}
Sometimes its easier to just use a timer.
using System.Threading;
...
private static Timer _myTimer;
private static volatile bool _isCancled;
private static void Main(string[] args)
{
_myTimer = new Timer(Callback, null, 2000, 2000);
Console.ReadLine();
}
private static void Callback(object state)
{
if (_isCancled)
{
_myTimer.Change(0, 0);
return;
}
try
{
//SendKeys.Send("KeyBoard Action");
Console.WriteLine("blah");
}
catch (Exception ex)
{
//Handle Exception
}
}
or another way
Task.Run(async () =>
{
while (!_isCancled)
{
await Task.Delay(2000);
//SendKeys.Send("KeyBoard Action");
Console.WriteLine("blah");
}
});
Just for completeness, the optimal way to cancel a task is using a Cancellation Token. You can read more about them here
CancellationToken Structure
Propagates notification that operations should be canceled.
Add a condition inside the for loop, so that it will exit when requested.
if (condition)
{
break;
}
Edit: Because of the Thread.Sleep everywhere, the program won't actually be able to have a conditional change, example, if you're condition was when the user pressed f1, the condition would never become true because the Thread.Sleep would block the thread, therefore the users input would never be recognized. Try not to use so many Thread.Sleep, if any at all. If it is absolutely necessary, I advise you to use an async method, or use Timers.
I have a simple program here below that has 2 threads performing some task.
Thread1 is the data feeder. Thread2 is the data processor.
So far the work being done through my approach is working but I want to have better way of getting notified when the work completes
Here is the code
class Program
{
private static BlockingCollection<int> _samples = new BlockingCollection<int>();
private static CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private static bool _cancel;
static void Main(string[] args)
{
ThreadStart thread1 = delegate
{
ProcessThread1();
};
new Thread(thread1).Start();
ThreadStart thread2 = delegate
{
ProcessThread2();
};
new Thread(thread2).Start();
Console.WriteLine("Press any key to cancel..");
Console.Read();
_cancel = true;
_cancellationTokenSource.Cancel();
Console.Read();
}
private static void ProcessThread1()
{
for (int i = 0; i < 10; i++)
{
if (_cancel)
{
break;
}
Console.WriteLine("Adding data..");
_samples.TryAdd(i,100);
Thread.Sleep(1000);
}
// I dont like this. Instead can I get notified in the UI thread that this thread is complete.
_cancel = true;
_cancellationTokenSource.Cancel();
}
private static void ProcessThread2()
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
int data;
if (_samples.TryTake(out data, 100))
{
// Do some work.
Console.WriteLine("Processing data..");
}
}
Console.WriteLine("Cancelled.");
}
}
I want the program to exit if the cancel is requested by the user or when the work completes.
I am not sure how I can get notified when the ProcessThread1 runs out of work. Currently I am setting cancel = true when the work is complete but it seem not right. Any help appreciated.
If you use Task instead of manually creating threads, you can attach a continuation on your task to notify your UI that the work is complete.
Task workOne = Task.Factory.StartNew( () => ProcessThread1());
workOne.ContinueWith(t =>
{
// Update UI here
}, TaskScheduler.FromCurrentSynchronizationContext());
With .NET 4.5, this becomes even easier, as you can potentially use the new async language support:
var workOne = Task.Run(ProcessThread1);
var workTwo = Task.Run(ProcessThread2);
// asynchronously wait for both tasks to complete...
await Task.WhenAll(workOne, workTwo);
// Update UI here.
Note that these both are designed with a user interface in mind - and will behave unusually in a console application, as there is no current synchronization context in a console application. When you move this to a true user interface, it will behave correctly.
Start one more thread whose only job is to wait on console input:
private void ConsoleInputProc()
{
Console.Write("Press Enter to cancel:");
Console.ReadLine();
_cancellationTokenSource.Cancel();
}
Your main thread then starts the two processing threads and the input thread.
// create and start the processing threads
Thread t1 = new Thread(thread1);
Thread t2 = new Thread(thread2);
t1.Start();
t2.Start();
// create and start the input thread
Thread inputThread = new Thread(ConsoleInputProc);
inputThread.Start();
Then, you wait on the two processing threads:
t1.Join();
// first thread finished. Request cancellation.
_cancellationTokenSource.Cancel();
t2.Join();
So if the user presses Enter, then the input thread sets the cancellation flags. thread1 and thread2 both see the cancellation request and exit.
If thread1 completes its work, then the main thread sets the cancellation flag and thread2 will cancel.
In either case, the program won't exit until thread 2 exits.
There's no need to kill the input thread explicitly. It will die when the program exits.
By the way, I would remove these lines from the thread 1 proc:
// I dont like this. Instead can I get notified in the UI thread that this thread is complete.
_cancel = true;
_cancellationTokenSource.Cancel();
I would remove the _cancel variable altogether, and have the first thread check IsCancellationRequested just like the second thread does.
It's unfortunate that you have to start a dedicated thread to wait on console input, but it's the only way I know of to accomplish this. The Windows console doesn't appear to have a waitable event.
Note that you could do this same thing with Task, which overall is easier to use. The code that the tasks perform would be the same.
Update
Looking at the bigger picture, I see that you have a typical producer/consumer setup with BlockingCollection. You can make your producer and consumer threads a lot cleaner:
private static void ProcessThread1()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Adding data..");
_samples.TryAdd(i, Timeout.Infinite, _cancellationTokenSource.Token);
// not sure why the sleep is here
Thread.Sleep(1000);
}
// Marks the queue as complete for adding.
// When the queue goes empty, the consumer will know that
// no more data is forthcoming.
_samples.CompleteAdding();
}
private static void ProcessThread2()
{
int data;
while (_samples.TryTake(out data, TimeSpan.Infinite, _cancellationTokenSource.Token))
{
// Do some work.
Console.WriteLine("Processing data..");
}
Console.WriteLine("Cancelled.");
}
You'll still need that input thread (unless you want to spin a loop on Console.KeyAvailable), but this greatly simplifies your producer and consumer.
While working on a large project I realized I was making a lot of calls to be scheduled in the future. Since these were fairly light-weight, I thought it might be better to use a separate scheduler.
ThreadPool.QueueUserWorkItem (() =>
{
Thread.Sleep (5000);
Foo (); // Call is to be executed after sometime
});
So I created a separate scheduler class that runs on its own thread and executes these events. I have 2 functions that access a shared queue from separate threads. I'd use a lock, but since one of the threads needs to sleep-wait, I wasn't sure how to release the lock.
class Scheduler
{
SortedDictionary <DateTime, Action> _queue;
EventWaitHandle _sync;
// Runs on its own thread
void Run ()
{
while (true)
{
// Calculate time till first event
// If queue empty, use pre-defined value
TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
// Execute action if in the next 100ms
if (timeDiff < 100ms)
...
// Wait on event handle for time
else
_sync.WaitOne (timeDiff);
}
}
// Can be called by any thread
void ScheduleEvent (Action action, DataTime time)
{
_queue.Add (time, action);
// Signal thread to wake up and check again
_sync.Set ();
}
}
The trouble is, I'm not sure how to synchronize access to the queue between the 2 functions. I can't use a monitor or mutex, because Run() will sleep-wait, thus causing a deadlock. What is the right synchronization mechanism to use here? (If there a mechanism to atomically start the sleep-wait process and immediately release the lock, that might solve my problem)
How can I verify there is no race-condition?
Is this a variation of the producer consumer problem, or is there a more relevant synchronization problem-description?
While this is somewhat geared towards C#, I'd be happy to hear a general solution to this. Thanks!
OK, take 2 with Monitor/Pulse.
void Run ()
{
while (true)
{
Action doit = null;
lock(_queueLock)
{
while (_queue.IsEmpty())
Monitor.Wait(_queueLock);
TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
if (timeDiff < 100ms)
doit = _queue.Dequeue();
}
if (doit != null)
; //execute doit
else
_sync.WaitOne (timeDiff);
}
}
void ScheduleEvent (Action action, DataTime time)
{
lock (_queueLock)
{
_queue.Add(time, action);
// Signal thread to wake up and check again
_sync.Set ();
if (_queue.Count == 1)
Monitor.Pulse(_queuLock);
}
}
The problem is easily solved, make sure the WaitOne is outside the lock.
//untested
while (true)
{
Action doit = null;
// Calculate time till first event
// If queue empty, use pre-defined value
lock(_queueLock)
{
TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
if (timeDiff < 100ms)
doit = _queue.Dequeue();
}
if (doit != null)
// execute it
else
_sync.WaitOne (timeDiff);
}
_queueLock is a private helper object.
Since your goal is to schedule a task after a particular period of time, why not just use the System.Threading.Timer? It doesn't require dedicating a thread for the scheduling and takes advantage of the OS to wake up a worker thread. I've used this (removed some comments and other timer service functionality):
public sealed class TimerService : ITimerService
{
public void WhenElapsed(TimeSpan duration, Action callback)
{
if (callback == null) throw new ArgumentNullException("callback");
//Set up state to allow cleanup after timer completes
var timerState = new TimerState(callback);
var timer = new Timer(OnTimerElapsed, timerState, Timeout.Infinite, Timeout.Infinite);
timerState.Timer = timer;
//Start the timer
timer.Change((int) duration.TotalMilliseconds, Timeout.Infinite);
}
private void OnTimerElapsed(Object state)
{
var timerState = (TimerState)state;
timerState.Timer.Dispose();
timerState.Callback();
}
private class TimerState
{
public Timer Timer { get; set; }
public Action Callback { get; private set; }
public TimerState(Action callback)
{
Callback = callback;
}
}
}
The monitores were created for this kind of situation, simple problems that can cost mutch for the application, i present my solution to this very simple and if u want to make a shutdown easy to implement:
void Run()
{
while(true)
lock(this)
{
int timeToSleep = getTimeToSleep() //check your list and return a value
if(timeToSleep <= 100)
action...
else
{
int currTime = Datetime.Now;
int currCount = yourList.Count;
try{
do{
Monitor.Wait(this,timeToSleep);
if(Datetime.now >= (tomeToSleep + currtime))
break; //time passed
else if(yourList.Count != currCount)
break; //new element added go check it
currTime = Datetime.Now;
}while(true);
}
}catch(ThreadInterruptedException e)
{
//do cleanup code or check for shutdown notification
}
}
}
}
void ScheduleEvent (Action action, DataTime time)
{
lock(this)
{
yourlist.add ...
Monitor.Pulse(this);
}
}