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);
}
}
}
Related
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();
}
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.");
}
}
}
/*My requirements is
one threads should print even numbers and the other should print odd numbers.
These threads should print the numbers in order (1, 2, 3, 4, 5...)
I have done this code but when my commenting either method countThreadOdd.Start() or countThreadEven.Start(), it is not printing only even or odd numbers.*/
class Program
{
static Object locker = new Object();
static LinkedList<int> number = new LinkedList<int>();
static int counter = 0;
static void Main(string[] args)
{
Thread countThreadOdd = new Thread(oddThread);
Thread countThreadEven = new Thread(evenThread);
//Thread Start
countThreadOdd.Start();
countThreadEven.Start();
//main thread will untill below thread is in exection mode
countThreadOdd.Join(10);
countThreadEven.Join(10);
Console.ReadLine();
}
//Odd Thread
public static void oddThread()
{
for (; counter < 10; )
{
//Lock the another thread to enter in critial area
lock (locker)
{
if (counter % 2 != 0)
{
Console.WriteLine(counter);
counter++;
}
}
}
}
//Even Thread
public static void evenThread()
{
for (; counter < 10; )
{
//Lock the another thread to enter in critial area
lock (locker)
{
if (counter % 2 == 0)
{
Console.WriteLine(counter);
counter++;
}
}
}
}
}
If you want to alternate between two threads, you can use two AutoResetEvent objects to do so, like so:
public static void oddThread()
{
for (int i = 1; i < 10; i +=2)
{
evenReady.WaitOne();
Console.WriteLine(i);
oddReady.Set();
}
}
public static void evenThread()
{
for (int i = 0; i < 10; i += 2)
{
oddReady.WaitOne();
Console.WriteLine(i);
evenReady.Set();
}
}
If you only want to run one of the threads, you can use a ManualResetEvent instead to effectively remove all locking.
A full example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Dmr.Common.Resources;
namespace Demo
{
class Program
{
static EventWaitHandle evenReady;
static EventWaitHandle oddReady;
static void Main(string[] args)
{
bool countOdd = true; // Change these to true/false as wanted.
bool countEven = true;
if (countOdd && countEven)
{
evenReady = new AutoResetEvent(false);
oddReady = new AutoResetEvent(true); // Must be true for the starting thread.
}
else
{
evenReady = new ManualResetEvent(true);
oddReady = new ManualResetEvent(true);
}
Thread countThreadOdd = new Thread(oddThread);
Thread countThreadEven = new Thread(evenThread);
//Thread Start
if (countOdd)
countThreadOdd.Start();
if (countEven)
countThreadEven.Start();
//main thread will untill below thread is in exection mode
if (countOdd)
countThreadOdd.Join();
if (countEven)
countThreadEven.Join();
Console.WriteLine("Done");
Console.ReadLine();
}
public static void oddThread()
{
for (int i = 1; i < 10; i +=2)
{
evenReady.WaitOne();
Console.WriteLine(i);
oddReady.Set();
}
}
public static void evenThread()
{
for (int i = 0; i < 10; i += 2)
{
oddReady.WaitOne();
Console.WriteLine(i);
evenReady.Set();
}
}
}
}
static AutoResetEvent evenReady = new AutoResetEvent(true);
static AutoResetEvent oddReady = new AutoResetEvent(false);
static void Main()
{
Thread countThreadOdd = new Thread(oddThread);
Thread countThreadEven = new Thread(evenThread);
countThreadOdd.Start();
countThreadEven.Start();
Console.WriteLine("Done");
Console.ReadLine();
}
public static void oddThread()
{
for (int i = 1; i < 10; i += 2)
{
oddReady.Set();
evenReady.WaitOne();
Console.WriteLine("Odd Thread: " + i);
//oddReady.Set();
}
}
public static void evenThread()
{
for (int i = 0; i < 10; i += 2)
{
oddReady.WaitOne();
evenReady.Set();
Console.WriteLine("Even Thread: " + i);
}
}
You can actually use Interlocked to communicate between threads. Interlocked allows you to share a variable concurrently across two threads.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace InterlockedTest
{
class Program
{
private static long _counter = 0;
private static void printEvenTask()
{
while (Interlocked.Read(ref _counter) < 100)
{
if (Interlocked.Read(ref _counter) % 2 == 0)
{
Console.WriteLine(Interlocked.Read(ref _counter));
Interlocked.Increment(ref _counter);
}
}
}
private static void printOddTask()
{
while (Interlocked.Read(ref _counter) < 100)
{
if (Interlocked.Read(ref _counter) % 2 == 1)
{
Console.WriteLine(Interlocked.Read(ref _counter));
Interlocked.Increment(ref _counter);
}
}
}
static void Main(string[] args)
{
Task oddTask = Task.Run(() => printOddTask());
Task evenTask = Task.Run(() => printEvenTask());
oddTask.Wait();
evenTask.Wait();
Console.ReadKey();
}
}
}
Try this method. It uses Task Library.
public class OddEvenThread
{
public static async Task printEvenNumber(int n)
{
for (int i = 1; i <= n; i++)
{
if (i % 2 == 0)
Console.WriteLine(i);
}
await Task.Delay(0);
}
private static async Task printOddNumbers(int n)
{
for (int i = 1; i <= n; i++)
{
if (i % 2 == 1)
Console.WriteLine(i);
}
await Task.Delay(0);
}
public async static Task printNumbers(int n)
{
Task evenNumbers = printEvenNumber(n);
Task oddNumbers = printOddNumbers(n);
List<Task> tasks = new List<Task>() { evenNumbers, oddNumbers };
await Task.WhenAll(tasks);
}
}
Using AutoResetEvent, threads can be made wait for each other. Here, two threads write numbers from 1 to 20:
using System;
using System.Threading;
namespace oddeven
{
class Program
{
static void Main(string[] args)
{
C c = new C();
Thread t1 = new Thread(c.PrintOdd);
Thread t2 = new Thread(c.PrintEven);
t1.Start();
t2.Start();
}
}
class C
{
AutoResetEvent e1 = new AutoResetEvent(true);
AutoResetEvent e2 = new AutoResetEvent(true);
int j = 1;
public void PrintOdd()
{
while (j < 20)
{
if (j % 2 != 0)
{
Console.WriteLine(j);
j++;
}
e1.Set();
e2.WaitOne();
}
}
public void PrintEven()
{
while (j <= 20)
{
e1.WaitOne();
if (j % 2 == 0)
{
Console.WriteLine(j);
j++;
}
e2.Set();
}
}
}
}
Good day!
I try to parallel my little example prog- for each 3600 iterations i create Task and starts it.
Should i stop it someway?
class Program
{
static void Main(string[] args)
{
int n=1000000;
List<Task> tasks = new List<Task>();
var sb = new StringBuilder();
for (int i = 0; i < n * 360; i++)
{
sb.Append("test");
if (i % 3600 == 0)
{
var task = Factory.GetTask(sb);
sb.Clear();
task.Start();
}
}
}
public static void WriteToFile(StringBuilder Sb)
{
// do work;
}
public sealed class Factory
{
private Factory()
{
}
public static Task GetTask(StringBuilder Sb)
{
return new Task(()=>Program.WriteToFile(Sb));
}
}
The Thread class has 4 different constructores:
Thread(ParameterizedThreadStart)
Thread(ThreadStart)
Thread(ParameterizedThreadStart, Int32)
Thread(ThreadStart, Int32)
But why this following code works?
class Program {
static void Main(string[] args) {
Thread t = new Thread(count2);
t.Start();
count1();
Console.ReadLine();
}
public static void count1() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("count1: " + i);
}
}
public static void count2() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("count2: " + i);
}
}
}
I don't pass the Thread constructore a ParameterizedThreadStart-delegate or a ThreadStart-delegate. I pass only a normal count2 method. But why this works?
That is because the compiler automatically adds a delegate construction for you, and it infers the type of delegate.
This page documents the exact feature.