I am making a C# console maths test where the user answers maths questions
I am trying to add a timer to the test, but I can't make my timer run at the same time as my other code
Here is an example of my code:
class Program
{
public static OtherCode()
{
\\*other code for test
}
public class Timer
{
public static int Timers(int timeLeft)
{
do
{
Console.Write("\rtimeLeft: {0} ", timeLeft);
timeLeft--;
Thread.Sleep(1000);
} while (timeLeft > 0);
Console.Write(Environment.NewLine);
return timeLeft;
}
}
public static void Main(string[] args)
{
int numberOfSeconds = 30;
Timer.Timers(numberOfSeconds);
\\other code
OtherCode();
}
}
I would like my timer to be running at the top of the console and the maths questions to be asked underneath like this except the question should be on a newline:
Any help appreciated!
UPDATE
When I add Console.SetCursorPosition() to my code like so:
do
{
Console.SetCursorPosition(0, 9);
Console.Write("\rtimeLeft: {0} ", timeLeft);
timeLeft--;
Thread.Sleep(1000);
} while (timeLeft > 0);
My code won't move the timer but when I type the answer to one of my maths questions it makes me type it on the same line as the timer like this:
In order to have a status message that stays at the bottom of the console you need a way to manipulate the screen buffer so you continuously overwrite your status message.
The Console.SetCursorPos can be used for this and is usefull in more advanced scenarios, but I think you can get by with simply using \r to reset the cursor to the beginning of the line.
Proof of consept:
using System;
namespace consoletimer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
int numberOfSeconds = 300;
var thread = new System.Threading.Thread(()=> PrintStatusMessage(numberOfSeconds));
thread.Start();
int n = 5;
while(n-- > 0){
WriteToScreen("Example text", false);
ReadInput();
System.Threading.Thread.Sleep(2000);
}
}
static void PrintStatusMessage(int numberOfSeconds){
var whenToStop = DateTime.Now.AddSeconds(numberOfSeconds);
while(DateTime.Now < whenToStop){
var timeLeft = (whenToStop-DateTime.Now).ToString(#"hh\:mm\:ss");
WriteToScreen($"Time Remaining: {timeLeft}", true);
System.Threading.Thread.Sleep(500);
}
}
static string ReadInput(){
string input = Console.ReadLine();
Console.Write(new string(' ',100));
Console.CursorLeft = 0;
return input;
}
static object lockObject = new object();
static void WriteToScreen(string message, bool resetCursor){
lock(lockObject){
if(resetCursor){
int leftPos = Console.CursorLeft;
Console.WriteLine();
Console.Write(message.PadRight( 50, ' '));
Console.CursorTop--;
Console.CursorLeft = leftPos;
}
else{
Console.WriteLine(message);
Console.Write(new string(' ',100));
Console.CursorLeft = 0;
}
}
}
}
}
Edit
We need to clear the next line whenever we write to the console so that we remove the status message that was there previously.
You can start the Timers method within a second Thread.
To do so you need to use System.Threading Namespace.
Take a look at:
Start Parameterized Thread
you can simply use threads this way
using System.Threading;
namespace ConsoleApp1
{
class Program
{
public static void OtherCode()
{
Console.ReadKey();
//other code for test
}
public static void Main(string[] args)
{
Thread thread = new Thread(new ThreadStart(Job));
thread.Start();
//other code
OtherCode();
}
public static void Job()
{
int numberOfSeconds = 30;
Timer.Timers(numberOfSeconds);
}
}
class Timer
{
public static int Timers(int timeLeft)
{
do
{
Console.Write("\rtimeLeft: {0} ", timeLeft);
timeLeft--;
Thread.Sleep(1000);
} while (timeLeft > 0);
Console.Write(Environment.NewLine);
return timeLeft;
}
}
}
or
public static void Main(string[] args)
{
Thread thread = new Thread(new ThreadStart(() => {
int numberOfSeconds = 30;
Timer.Timers(numberOfSeconds);
}));
thread.Start();
//other code
OtherCode();
}
Related
I have a static class A which has a public static ConcurrentQueue.
This class has a method which calls a method of another static class B.
In this method of static class B, a worker thread is started which polls for items in the static ConcurrentQueue of class A. If found, it dequeues the item and processes it.
The same method in class B also starts another thread which checks if the queue of class A is being constantly filled. If the filling occasionally is somehow stuck, a call to a static method in class A is made which resets and restarts the process.
And here comes the problem: When I restart the filling, items are inserted again into the static queue of static class A. But my thread in static class B which checks for items in the queue does not find any items anymore.
So my idea is that in class B I somehow lost the reference to the original static queue of class A. I think I oversee here some principles of static classes, but can not figure out what exactly.
EDIT: Here are some more details.
Main:
public static void Main(string[] args)
{
B.Initialize(8);
A.StartDataStream();
Console.ReadKey();
}
Class A:
class A
{
private static ACOMObject MyCOMObjekt;
public static ConcurrentQueue<PriceItem> Prices = new ConcurrentQueue<PriceItem>();
public static void StartDataStream()
{
DataStream myDataStream = GetDataStream();
FillStream(myDataStream);
B.StartHeartbeatCheck();
Console.WriteLine("Press Key to Exit Stream Call.");
Console.ReadKey();
GC.KeepAlive(myDataStream);
GC.KeepAlive(MyCOMObjekt);
}
private static DataStream GetDataStream()
{
if (MyCOMObjekt== null)
{
MyCOMObjekt= new ACOMObject ();
}
return (DataStream) MyCOMObjekt.DataStream;
}
private static void FillStream(DataStream myDataStream)
{
foreach (var symbol in Symbols.SymbolList)
{
myDataStream.Add(symbolNr, 1);
}
myDataStream.Bid += new _IDataStreamEvents_BidEventHandler(myDataStream_Bid);
myDataStream.Ask += new _IDataStreamEvents_AskEventHandler(myDataStream_Ask);
}
private static void myDataStream_Bid(int SymbolNr, float Price, DateTime Time)
{
PriceItem p;
p.SymbolNr = SymbolNr;
p.Price = Price;
p.Time = Time;
p.IsBid = true;
Prices.Enqueue(p);
}
private static void myDataStream_Ask(int SymbolNr, float Price, DateTime Time)
{
PriceItem p;
p.SymbolNr = SymbolNr;
p.Price = Kurs;
p.Time = Zeit;
p.IsBid = false;
Prices.Enqueue(p);
}
public static void RestartMyCOMProcess()
{
try
{
Process proc = Process.GetProcessesByName("MyCOMProcess")[0];
proc.Kill();
}
catch (Exception)
{
//No Process = fine
}
MyCOMObjekt = null;
DataStream myDataStream = GetDataStream();
myDataStream.Bid -= new _IDataStreamEvents_BidEventHandler(myDataStream_Bid); //probably not necessary...
myDataStream.Ask -= new _IDataStreamEvents_AskEventHandler(myDataStream_Ask); //probably not necessary...
FillStream(myDataStream);
}
}
Class B:
class B
{
private static int countPrices; //Incremented every time a price is taken out of Price Queue
public static void Initialize(int numberOfWorkerThreads)
{
StartWorkers(numberOfWorkerThreads);
}
public static void StartWorkers(int number)
{
for (int j = 0; j < number; j++)
{
Thread t = new Thread(ScanForPrices);
t.Name = "ScanForPrices" + j;
t.Start();
}
}
private static void ScanForPrices()
{
try
{
while (true)
{
PriceItem p;
if (A.Prices.TryDequeue(out p))
{
if (p.IsBid)
{
AnalyzeBidPrice(p);
}
else
{
HandleAskPrice(p);
}
Interlocked.Increment(ref countPrices)
}
else
{
Thread.Sleep(1);
}
}
}
catch (ThreadAbortException)
{
Console.WriteLine("Price Scan Thread aborted.");
}
}
public static void StartHeartbeatCheck()
{
Thread t = new Thread(CheckHeartBeat);
t.Name = "CheckHeartBeat";
t.Start();
}
private static void CheckHeartBeat()
{
TimeSpan start = new TimeSpan(09, 0, 0); //09 o'clock
TimeSpan end = new TimeSpan(20, 0, 0); //20 o'clock
TimeSpan stopTime = new TimeSpan(20, 5, 0); //20 o'clock and 5 minutes
int countSuccessiveBlockings = 0;
try
{
while (true)
{
Thread.Sleep(5000);
TimeSpan now = DateTime.Now.TimeOfDay;
if ((now > start) && (now < end))
{
int countOld = countPrices;
Thread.Sleep(1000);
if (countOld == countPrices)
{
Console.WriteLine(DateTime.Now + ": Price Stream blocked!");
countSuccessiveBlockings++;
}
else
{
countSuccessiveBlockings = 0;
}
if (countSuccessiveBlockings > 2)
{
A.RestartMyCOMProcess();
countSuccessiveBlockings = 0;
}
}
}
}
catch (ThreadAbortException)
{
Console.WriteLine("Heartbeat Thread aborted.");
}
}
}
I am new to multi-thread programming in C#. My problem is that I don't know how to wait for a method that is being run on another thread to finish, before it can continue to the next line. For example, something like this
public class A
{
int i;
public A()
{
i = 0;
}
protected void RunLoop()
{
while(i < 100)
{
i++;
}
}
public void Start()
{
TimerResolution.TimeBeginPeriod(1);
runThread = new Thread(new ThreadStart(RunLoop));
running = true;
runThread.Start();
}
}
public class B
{
A classAInstance = new A();
A.Start();
Console.Writeline(i);
}
Right now, it prints 0 on the console, which is not what I want (i.e. i = 100).
What is the best way to do this? BTW, I don't have access to the runThread that is created in class A
Thanks.
EDIT:
It was a bit difficult to solve this problem without modifying a lot codes. Therefore, we ended up with adding a condition in the public void Start() with which it can decide whether to run the RunLoop in a separate thread or not. The condition was defined using an Enum field.
public void Start()
{
TimerResolution.TimeBeginPeriod(1);
running = true;
if (runningMode == RunningMode.Asynchronous)
{
runThread = new Thread(new ThreadStart(RunLoop));
runThread.Start();
}
else
{
RunLoop();
}
}
And
public enum RunningMode { Asynchronous, Synchronous };
Thanks everyone for help.
The preferred method is to use the Task Parallel Library (TPL) and use Task with await.
If you must use Threads, then use a ManualResetEvent or ManualResetEventSlim to signal the end of a method.
void Main()
{
var a = new A();
a.Start();
a.FinishedEvent.WaitOne();
Console.WriteLine(a.Index);
}
// Define other methods and classes here
public class A
{
ManualResetEvent mre = new ManualResetEvent(false);
int i;
public EventWaitHandle FinishedEvent
{
get { return mre; }
}
public int Index
{
get { return i; }
}
public A()
{
i = 0;
}
protected void RunLoop()
{
while (i < 1000)
{
i++;
}
mre.Set();
}
public void Start()
{
var runThread = new Thread(new ThreadStart(RunLoop));
runThread.Start();
}
}
Your life would be so much better with tasks.
Your code could be this simple:
var task = Task.Factory.StartNew(() =>
{
var i = 0;
while (i < 100)
{
i++;
}
return i;
});
Console.WriteLine(task.Result);
I like use Monitor.Wait() and Monitor.Pulse() in conjunction with "lock" operator. It works, but you must be careful, when you use this technique.
I'm added some changes to your code to demonstrate it. Code below are prints i== 100, as you want.
public class A
{
int i;
public object SyncObject
{ get; private set; }
public A()
{
SyncObject = new object();
i = 0;
}
protected void RunLoop()
{
while (i < 100)
{
i++;
}
lock (SyncObject)
{
Monitor.Pulse(SyncObject);
}
}
public void Start()
{
var runThread = new Thread(new ThreadStart(RunLoop));
runThread.Start();
}
public void PrintI()
{
Console.WriteLine("I == " + i);
}
}
public class B
{
public static void Run()
{
A classAInstance = new A();
lock (classAInstance.SyncObject)
{
classAInstance.Start();
Monitor.Wait(classAInstance.SyncObject);
}
classAInstance.PrintI();
}
}
The question is that, what happens to a thread when the function has already been executed and the thread is started in that function. (please see an example below)
public int Intialise ()
{
int i = startServer();
Thread readall = new Thread(readAllMessage);
if (i == 1)
readall.Start();
else
MessageBox.Show("Connection Error");
return i;
}
I want 'readall' to continue (forever or till the application is closed) even if the function is executed. Is it possible? Because for me the thread stops immediately even when the true condition is met. Please shed some light.
OK, here is your code slightly modified to include the loop.
internal class Program
{
public static int Intialise()
{
int i = startServer();
Thread readall = new Thread(readAllMessage);
readall.IsBackground = true; // so that when the main thread finishes, the app closes
if (i == 1)
readall.Start();
else
Console.WriteLine("Error");
return i;
}
public static void readAllMessage()
{
while (true)
{
Console.WriteLine("reading...");
Thread.Sleep(500);
}
}
public static int startServer()
{
return 1;
}
private static void Main(string[] args)
{
var i = Intialise();
Console.WriteLine("Init finished, thread running");
Console.ReadLine();
}
}
when you run it, it will print:
Init finished, thread running
reading...
reading...
reading...
and when you press enter (see Console.ReadLine()) it will stop running.
If you change the IsBackground to TRUE it would not exit the process.
Here is an example of what you ask
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ForeverApp
{
class SomeObj
{
public void ExecuteForever()
{
while (true)
{
Thread.Sleep(1000);
Console.Write(".");
}
}
}
class Program
{
static void Main(string[] args)
{
SomeObj so = new SomeObj();
Thread thrd = new Thread(so.ExecuteForever);
thrd.Start();
Console.WriteLine("Exiting Main Function");
}
}
}
I'm creating a class library with a method, for example, OnetoTen(), which basically is a for loop counting from 1 to 10. What i'm trying to achieve is to call this method from another program and have it output what number/iteration the for loop is currently at.
Is the use of delegates/events the right way to go?
You could use a callback (delegate) or an event.
Example using callback:
class Program
{
static void Main(string[] args)
{
var counter = new Counter();
counter.CountUsingCallback(WriteProgress);
Console.ReadKey();
}
private static void WriteProgress(int progress, int total){
Console.WriteLine("Progress {0}/{1}", progress, total);
}
}
public class Counter
{
public void CountUsingCallback(Action<int, int> callback)
{
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(1000);
callback(i + 1, 10);
}
}
}
Example using event:
class Program
{
static void Main(string[] args)
{
var counter = new Counter();
counter.ProgessTick += WriteProgress;
counter.CountUsingEvent();
Console.ReadKey();
}
private static void WriteProgress(int progress, int total){
Console.WriteLine("Progress {0}/{1}", progress, total);
}
}
public class Counter
{
public event Action<int, int> ProgessTick;
public void CountUsingEvent()
{
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(1000);
if (ProgessTick != null)
ProgessTick(i + 1, 10);
}
}
}
I am writing a read-write synchronization class, and would like some advice on what I to do next. For some reason, it sometimes allows a Read to happen in the middle of a Write, and I cannot find the reason.
This is what I want from this class:
Reads not allowed at the same time as writes.
Multiples reads can happen at the same time.
Only one write can happen at a time.
When a write is needed, all already executing reads continue,
no new reads are allowed, when all reads finish the write executes.
I know that .Net framework has a class to do this... but what I want is to understand and to reproduce something like that. I'm not reinventing the wheel, I am trying to understand it by making my own wheel... happens that my wheel is kinda squared a bit.
What I have currently is this:
public class ReadWriteSync
{
private ManualResetEvent read = new ManualResetEvent(true);
private volatile int readingBlocks = 0;
private AutoResetEvent write = new AutoResetEvent(true);
private object locker = new object();
public IDisposable ReadLock()
{
lock (this.locker)
{
this.write.Reset();
Interlocked.Increment(ref this.readingBlocks);
this.read.WaitOne();
}
return new Disposer(() =>
{
if (Interlocked.Decrement(ref this.readingBlocks) == 0)
this.write.Set();
});
}
public IDisposable WriteLock()
{
lock (this.locker)
{
this.read.Reset();
this.write.WaitOne();
}
return new Disposer(() =>
{
this.read.Set();
if (this.readingBlocks == 0)
this.write.Set();
});
}
class Disposer : IDisposable
{
Action disposer;
public Disposer(Action disposer) { this.disposer = disposer; }
public void Dispose() { this.disposer(); }
}
}
This is my test program... when something goes wrong it prints the lines in red.
class Program
{
static ReadWriteSync sync = new ReadWriteSync();
static void Main(string[] args)
{
Console.BackgroundColor = ConsoleColor.DarkGray;
Console.ForegroundColor = ConsoleColor.Gray;
Console.Clear();
Task readTask1 = new Task(() => DoReads("A", 20));
Task readTask2 = new Task(() => DoReads("B", 30));
Task readTask3 = new Task(() => DoReads("C", 40));
Task readTask4 = new Task(() => DoReads("D", 50));
Task writeTask1 = new Task(() => DoWrites("E", 500));
Task writeTask2 = new Task(() => DoWrites("F", 200));
readTask1.Start();
readTask2.Start();
readTask3.Start();
readTask4.Start();
writeTask1.Start();
writeTask2.Start();
Task.WaitAll(
readTask1, readTask2, readTask3, readTask4,
writeTask1, writeTask2);
}
static volatile bool reading;
static volatile bool writing;
static void DoWrites(string name, int interval)
{
for (int i = 1; i < int.MaxValue; i += 2)
{
using (sync.WriteLock())
{
Console.ForegroundColor = (writing || reading) ? ConsoleColor.Red : ConsoleColor.Gray;
writing = true;
Console.WriteLine("WRITE {1}-{0} BEGIN", i, name);
Thread.Sleep(interval);
Console.WriteLine("WRITE {1}-{0} END", i, name);
writing = false;
}
Thread.Sleep(interval);
}
}
static void DoReads(string name, int interval)
{
for (int i = 0; i < int.MaxValue; i += 2)
{
using (sync.ReadLock())
{
Console.ForegroundColor = (writing) ? ConsoleColor.Red : ConsoleColor.Gray;
reading = true;
Console.WriteLine("READ {1}-{0} BEGIN", i, name);
Thread.Sleep(interval * 3);
Console.WriteLine("READ {1}-{0} END", i, name);
reading = false;
}
Thread.Sleep(interval);
}
}
}
What is wrong with all this... any advice on how to do it correctly?
The primary issue that I see is that you are trying to make reset events encompass both the meanings of a read/write and the handling of their current state, without synchronizing in a consistent manner.
Here's an example of how the inconsistent synchronization may bite you in your specific code.
A write is disposing and a read is coming in.
The read acquires the lock
The write sets the read ManualResetEvent (MRE)
The write checks the current read count, finding 0
The read resets the write AutoResetEvent (ARE)
The read increments the read count
The read finds its MRE has been set and begins to read
All is fine so far, but the write hasn't finished yet...
A second write comes in and acquires the lock
The second write resets the read MRE
The first write finishes by setting the write ARE
The second write finds its ARE has been set and begins to write
When thinking about multiple threads, unless you are within a lock of some sort, you must take the view that all other data is wildly fluctuating and cannot be trusted.
A naive implementation of this may split out the queueing logic from the state logic and synchronize appropriately.
public class ReadWrite
{
private static int readerCount = 0;
private static int writerCount = 0;
private int pendingReaderCount = 0;
private int pendingWriterCount = 0;
private readonly object decision = new object();
private class WakeLock:IDisposable
{
private readonly object wakeLock;
public WakeLock(object wakeLock) { this.wakeLock = wakeLock; }
public virtual void Dispose() { lock(this.wakeLock) Monitor.PulseAll(this.wakeLock); }
}
private class ReadLock:WakeLock
{
public ReadLock(object wakeLock) : base(wakeLock) { Interlocked.Increment(ref readerCount); }
public override void Dispose()
{
Interlocked.Decrement(ref readerCount);
base.Dispose();
}
}
private class WriteLock:WakeLock
{
public WriteLock(object wakeLock) : base(wakeLock) { Interlocked.Increment(ref writerCount); }
public override void Dispose()
{
Interlocked.Decrement(ref writerCount);
base.Dispose();
}
}
public IDisposable TakeReadLock()
{
lock(decision)
{
pendingReaderCount++;
while (pendingWriterCount > 0 || Thread.VolatileRead(ref writerCount) > 0)
Monitor.Wait(decision);
pendingReaderCount--;
return new ReadLock(this.decision);
}
}
public IDisposable TakeWriteLock()
{
lock(decision)
{
pendingWriterCount++;
while (Thread.VolatileRead(ref readerCount) > 0 || Thread.VolatileRead(ref writerCount) > 0)
Monitor.Wait(decision);
pendingWriterCount--;
return new WriteLock(this.decision);
}
}
}