threading timer not working, why? - c#

i have a program which i have a threading timer to update the time coming from the data server. However, i notice the timer run a few times and stop calling afterwards. i try and copy the threading timer code onto a new program and it runs fine, so i know somehow the timer code must have interfere with the rest of the program, but i dont know where, can anyone help me out please?
the program is quite big to post everything here, i try to post all the relevant parts here.
public partial class HistoricalDownload : Form
{
static int column = 2;
static int row = 100;
string timeFmt = "yyyy/MM/dd HH:mm:ss.fff";
ZenFire.Connection zf;
ZenFire.Connection.TickEventHandler tick;
ZenFire.IProduct product = null;
System.Windows.Forms.TextBox[,] textbox = new System.Windows.Forms.TextBox[column, row];
DisplayTimer displayTimer = new DisplayTimer();
memoryStreamClass msc = new memoryStreamClass();
Dictionary<string, int> dictionarySymbol = new Dictionary<String, int>();
delegate void StringParameterDelegate(int j, string value);
public HistoricalDownload(ZenFire.Connection z)
{
InitializeComponent();
int month = 0;
int year = 0;
string symbol;
string exchange;
string finalSymbol;
string[] lineSplit;
zf = z;
tick = new ZenFire.Connection.TickEventHandler(zf_TickEvent);
zf.TickEvent += tick;
//set the array for name and update time
for (int k = 0; k < column; k++)
{
for (int j = 0; j < row; j++)
{
textbox[k, j] = new System.Windows.Forms.TextBox();
textbox[k, j].Size = new Size(140, 18);
textbox[k, j].Name = "textbox_" + k + "_" + j;
if (j >= 50)
{
textbox[k, j].Location = new System.Drawing.Point((k * 140) + 400, ((j - 50) * 18) + 30);
}
else
{
textbox[k, j].Location = new System.Drawing.Point((k * 140) + 20, (j * 18) + 30);
}
textbox[k, j].Visible = true;
Controls.Add(textbox[k, j]);
}
}
//load the config file and subscribe the symbol
....
///////////////////////////////////////
System.Threading.TimerCallback displayCallback = new System.Threading.TimerCallback(timeDisplay);
System.Threading.Timer displayTimerThread = new System.Threading.Timer(displayCallback, displayTimer, 0, 1000);
}
public void timeDisplay(object timerObject)
{
DisplayTimer t = (DisplayTimer)timerObject;
for (int j = 0; j < t.row; j++)
{
string value = t.outputTime[j].ToString(timeFmt);
if (value != "0001/01/01 00:00:00.000")
{
writeToTextBox(j, value);
}
}
}
public void writeToTextBox(int j, string value)
{
if (InvokeRequired)
{
BeginInvoke(new StringParameterDelegate(writeToTextBox), new object[] { j, value });
return;
}
//// Must be on the UI thread if we've got this far
textbox[1, j].Text = value;
}
void zf_TickEvent(object sender, ZenFire.TickEventArgs e)
{
string product = e.Product.ToString();
int c = dictionarySymbol[product];
displayTimer.outputTime[c] = e.TimeStamp;
msc.fillBuffer(string.Format("{0},{1},{2},{3},{4}\r\n",
e.TimeStamp.ToString(timeFmt),
product,
Enum.GetName(typeof(ZenFire.TickType), e.Type),
e.Price,
e.Volume));
}
can anyone points out where the interference might be?

If all your're doing in your timer callback is updating the UI, I'd suggest using System.Windows.Forms.Timer instead. You don't have to deal with InvokeRequired/BeginInvoke because that handler runs on the UI thread.
It also appears that you using a local variable for your System.Thread.Timer. That could cause the timer to be finalized after the execution of HistoricalDownload. Which is probably much sooner than you want the timer to stop running. (see first Note at http://msdn.microsoft.com/en-us/library/saba8ksx) You should put that variable in a field of the parent class--or whatever class will stay "alive" as long as you want the timer to run. I don't think that would be an issue if you used System.Windows.Forms.Timer. But, it's a good idea too keep a field around for something that get's used asynchronously.

The Tick event for the timer may be occurring on a ThreadPool thread (many of the framework timers do this, but since you're using a custom timer (ZenFire?), it's impossible to know for sure).
If this is the case, your code is likely not thread safe, and you may be getting an exception within your timer's Tick event. Again, depending on the implementation, the exception may be preventing the timer from functioning correctly after that point.
The particular things to watch for are to not update any UI components from the timer's Tick event - but install, marshal the calls back to the UI thread with Control.Invoke (or Dispatcher.Invoke if you're using WPF). Also, simple things like using your Dictionary<T,U> are not thread safe, so you should synchronize access to these items.

Related

How do I keep different threads to have their own variable calculations?

So it takes too long, if I try to do this code in serialization. So I want to do it with threading. But I'm running into safety-problems. Here is what starts the threads:
protected void Page_LoadComplete(object sender, EventArgs e)
{
if (!IsPostBack)
{
using (var finished = new CountdownEvent(1))
{
for (int i = 1; i <= Convert.ToInt32(ViewState["Count"]); i++)
{
string k = i.ToString();
ThreadInfo threadInfo = new ThreadInfo();
threadInfo.f = k;
finished.AddCount(); // Indicate that there is another work item.
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
Debug.WriteLine("Thread-Start Part " + k.ToString());
CalcThread(threadInfo);
}
finally
{
finished.Signal(); // Signal that the work item is complete.
}
}, null);
Thread.Sleep(300);
}
Debug.WriteLine("Waiting till threads are done! ");
finished.Signal(); // Signal that queueing is complete.
finished.Wait(); // Wait for all work items to complete.
Debug.WriteLine("Threads have completed! ");
}
}
Here is one place that I believe I'm getting some unsafe conditions, and I really don't know if there is a way to solve the problems. I cannot Lock ( ... ) all the code. Because that would defeat the purpose. So a lot of the calculations happen in a sub-class. The problem, I believe is when this sub-class is called, in multiple threads... the answers I'm getting back are often the same answers.
m_calculation.StartQuotePart(runnerweight, waste, machinesize, injectioncycle, volumefactor, MOQ);
m_calculation.partCostNoShiping = m_calculation.partCostNoShiping / partquantity * (1.0 + partcommission);
m_calculation.FedExShippingCost = m_calculation.FedExShippingCost / partquantity * (1.0 + partcommission);
m_calculation.DHLShippingCost = m_calculation.DHLShippingCost / partquantity * (1.0 + partcommission);
m_calculation.UPSShippingCost = m_calculation.UPSShippingCost / partquantity * (1.0 + partcommission);
m_calculation.OceanShippingCost = m_calculation.OceanShippingCost / partquantity * (1.0 + partcommission);
m_calculation.materialcost_out = m_calculation.materialcost_out / partquantity;
m_calculation.ProcessCost_out = m_calculation.ProcessCost_out / partquantity;
m_calculation.DHLshippingcost_out = m_calculation.DHLshippingcost_out / partquantity;
I have an instance for m_calculation... in the same class that is kicking off the threads. Is there a better way to access it, that wouldn't cause the issues. Is there a better way to create the threads that would cause the variable-mis-mash? This is supposed to run during the 'Page-Load-Complete' and then wait for the threads to complete with 'Finish-Wait'
Edit: I'm updating the Load-Complete with this based on jjxtra's post...
int count = Convert.ToInt32(ViewState["Count"]);
var tasks = new Task[count];
for (int i = 1; i <= count; i++)
{
string k = i.ToString();
ThreadInfo threadInfo = new ThreadInfo();
threadInfo.f = k;
tasks[i - 1] = Task.Factory.StartNew(() =>
{
CalcThread(threadInfo);
});
}
Task.WaitAll(tasks);
That's what the state object is for, you can pass an object to the thread, let it modify that object in isolation and then execute some sort of callback at the end of the thread to another method, or you can use the Join method to wait for the work to complete.
Instead of pasing null to QueueUserWorkItem, pass an instance of a class with everything the thread needs to do it's work and report results.
Having said all this, if you switch to using Task everything might be much simpler, but not sure what version of .NET / .NET core you are using...

Checking if instance is null VS calling empty function (C#)

Introduction
So I was making a game, thinking how do I structure and update all my game objects. Do I (case 1) create a simple GameObj as a parent class and put some physics in virtual Update method, some default drawing in virtual Draw, etc, and make every other object (wall, enemy, player...) be the child, OR do I (case 2) use components as described in this article. In short, the writer explains that we could make interfaces for user input, physics update and draw (lets stop at those 3) and describe our GameObj with preprogrammed instances of these interfaces.
Now, in both cases I will get a loop of GameObj class.
In case 1 it would probably look something like this
// in Update function of the level class
for(int i = 0; i < gameObjList.Count; i++)
{
gameObjList[i].Update();
}
And in case 2, something like this
// in UpdatePhysics function of the level class
for(int i = 0; i < gameObjList.Count; i++)
{
gameObjList[i].PhysicComponent.Update();
}
And so on (in case 2) for other interfaces such as InputComponent.Update and DrawComponent.Draw (or CollisionComponent.Check(gameObj[x]), I dunno).
Reasons listed are ment to be inside a level class that takes care of all of our game objects
Reasons to consider if ( x != null )
In both cases we (could) have a situation where we need to call if ( x != null ). In case 1 we maybe don't want to delete and add to the gameObjList all the time, but recycle the instances, so we set them to null without doing something along the lines of gameObjList.Remove(x). In case 2 maybe we want to be able not to set some of the components, so we'd have to ask if (gameObjList[i].someComponent != null) to be able to call gameObjList[i].someComponent.Update().
Reasons to consider calling empty function
Also in both cases, we could just call an empty function (e.g. public void myFunction(){}). Lets consider the self explanatory Wall class. It exists just to be there. Id doesn't update, but it does have a certain relation to other GameObjs. Also, some of it's children in case 1, like a lets say MovingWall or Platform would have some sort of update. As for case 2, we could always declare a default, empty class of someComponent whose Update function would be empty, and so an instance of this class would be set to our GameObj component if none is set in the constructor. Maybe something like this
public GameObj(IPhysicsComponent physicsComponent, ...){
if(physicsComponent == null)
physicsComponent = PhysicsComponent.Default;
this.physicsComponent = physicsComponent;
}
Research
Now, I didn't find what would be the most efficient thing to do in a game engine we are building here. Here are some examples I just tested (note some of them are just for reference):
1. empty loop
2. empty function
3. if(x != null) x.empyFunction(); x is always null
4. x?.emptyFunction(); x is always null
5. if(x != null) x.empyFunction(); x is not null
6. x?.emptyFunction(); x is not null
7. myClass.staticEmptyFunction();
These 7 points are tested 100 000 times, 10 000 times. The code below is the code that I tested with. You can run in locally, change some of the static variables, and the result will appear in "result.txt" in the folder where you ran the program. Here is the code :
public enum TimeType
{
emptyLoop = 1,
loopEmptyFunction = 2,
loopNullCheck = 3,
loopNullCheckShort = 4,
loopNullCheckInstanceNotNull = 5,
loopNullCheckInstanceNotNullShort = 6,
loopEmptyStaticFunction = 7
}
class myTime
{
public double miliseconds { get; set; }
public long ticks { get; set; }
public TimeType type { get; set; }
public myTime() { }
public myTime(Stopwatch stopwatch, TimeType type)
{
miliseconds = stopwatch.Elapsed.TotalMilliseconds;
ticks = stopwatch.ElapsedTicks;
this.type = type;
}
}
class myClass
{
public static void staticEmptyFunction() { }
public void emptyFunction() { }
}
class Program
{
static List<myTime> timesList = new List<myTime>();
static int testTimesCount = 10000;
static int oneTestDuration = 100000;
static void RunTest()
{
Stopwatch stopwatch = new Stopwatch();
Console.Write("TEST ");
for (int j = 0; j < testTimesCount; j++)
{
Console.Write("{0}, ", j + 1);
myClass myInstance = null;
// 1. EMPTY LOOP
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)1));
stopwatch.Reset();
// 3. LOOP WITH NULL CHECKING (INSTANCE IS NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
if (myInstance != null)
myInstance.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)3));
stopwatch.Reset();
// 4. LOOP WITH SHORT NULL CHECKING (INSTANCE IS NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myInstance?.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)4));
stopwatch.Reset();
myInstance = new myClass();
// 2. LOOP WITH EMPTY FUNCTION
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myInstance.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)2));
stopwatch.Reset();
// 5. LOOP WITH NULL CHECKING (INSTANCE IS NOT NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
if (myInstance != null)
myInstance.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)5));
stopwatch.Reset();
// 6. LOOP WITH SHORT NULL CHECKING (INSTANCE IS NOT NULL)
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myInstance?.emptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)6));
stopwatch.Reset();
// 7. LOOP WITH STATIC FUNCTION
stopwatch.Start();
for (int i = 0; i < oneTestDuration; i++)
{
myClass.staticEmptyFunction();
}
stopwatch.Stop();
timesList.Add(new myTime(stopwatch, (TimeType)7));
stopwatch.Reset();
}
Console.WriteLine("\nDONE TESTING");
}
static void GetResults()
{
// SUMS
double sum1t, sum2t, sum3t, sum4t, sum5t, sum6t, sum7t,
sum1m, sum2m, sum3m, sum4m, sum5m, sum6m, sum7m;
sum1t = sum2t = sum3t = sum4t = sum5t = sum6t = sum7t =
sum1m = sum2m = sum3m = sum4m = sum5m = sum6m = sum7m = 0;
foreach (myTime time in timesList)
{
switch (time.type)
{
case (TimeType)1: sum1t += time.ticks; sum1m += time.miliseconds; break;
case (TimeType)2: sum2t += time.ticks; sum2m += time.miliseconds; break;
case (TimeType)3: sum3t += time.ticks; sum3m += time.miliseconds; break;
case (TimeType)4: sum4t += time.ticks; sum4m += time.miliseconds; break;
case (TimeType)5: sum5t += time.ticks; sum5m += time.miliseconds; break;
case (TimeType)6: sum6t += time.ticks; sum6m += time.miliseconds; break;
case (TimeType)7: sum7t += time.ticks; sum7m += time.miliseconds; break;
}
}
// AVERAGES
double avg1t, avg2t, avg3t, avg4t, avg5t, avg6t, avg7t,
avg1m, avg2m, avg3m, avg4m, avg5m, avg6m, avg7m;
avg1t = sum1t / (double)testTimesCount;
avg2t = sum2t / (double)testTimesCount;
avg3t = sum3t / (double)testTimesCount;
avg4t = sum4t / (double)testTimesCount;
avg5t = sum5t / (double)testTimesCount;
avg6t = sum6t / (double)testTimesCount;
avg7t = sum7t / (double)testTimesCount;
avg1m = sum1m / (double)testTimesCount;
avg2m = sum2m / (double)testTimesCount;
avg3m = sum3m / (double)testTimesCount;
avg4m = sum4m / (double)testTimesCount;
avg5m = sum5m / (double)testTimesCount;
avg6m = sum6m / (double)testTimesCount;
avg7m = sum7m / (double)testTimesCount;
string fileName = "/result.txt";
using (StreamWriter tr = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + fileName))
{
tr.WriteLine(((TimeType)1).ToString() + "\t" + avg1t + "\t" + avg1m);
tr.WriteLine(((TimeType)2).ToString() + "\t" + avg2t + "\t" + avg2m);
tr.WriteLine(((TimeType)3).ToString() + "\t" + avg3t + "\t" + avg3m);
tr.WriteLine(((TimeType)4).ToString() + "\t" + avg4t + "\t" + avg4m);
tr.WriteLine(((TimeType)5).ToString() + "\t" + avg5t + "\t" + avg5m);
tr.WriteLine(((TimeType)6).ToString() + "\t" + avg6t + "\t" + avg6m);
tr.WriteLine(((TimeType)7).ToString() + "\t" + avg7t + "\t" + avg7m);
}
}
static void Main(string[] args)
{
RunTest();
GetResults();
Console.ReadLine();
}
}
When I put all the data in excel and made a chart, it looked like this (DEBUG):
EDIT - RELEASE version. I guess this answers my question.
The questions are
Q1. What approach to use to be more efficient?
Q2. In what case?
Q3. Is there official documentation on this?
Q4. Did anybody else test this, maybe more intensively?
Q5. Is there a better way to test this (is my code at fault)?
Q6. Is there a better way around the problem of huge lists of instances that need to be quickly and efficiently updated, as in - every frame?
EDIT Q7. Why does the static method take so much longer to execute in the release version?
As #grek40 suggested, I did another test where I called myClass.staticEmptyFunction(); 100 times before starting the test so that it can be cashed. I also did set testTimesCount to 10 000 and oneTestDuration to 1 000 000. Here are the results:
Now, it seems much more stable. Even the little differences you can spot I blame on my google chrome, excel and deluge running in the background. The questions I asked I asked because I thought that there would be a greater difference, but I guess that the optimisation worsk much much better than I expected. I also guess that nobody did this test because they probably knew that there's C behind it, and that people did amasing work on the optimisation.

Delay in a WinForms app without using "await Task.Delay(x)"

I'm creating a poker app and i want to make some sort of simulation of the throwing of the cards effect and to do that I currently use await Task.Delay(x); However this requires async Task and if i switch this method where i do the task.delay(x) to async i will have to change at least 5-6 more into async as well. I suppose this is fine for someone that understand the exact way the asynchronus works. Currently im getting a lot of logic errors simply because i obviously don't know how async and await operators work.. In other words I'm newbie, and is there any alternative to this exact line await Task.Delay(x); I wont use anything else that is connected to async just this line.
Here's the code :
private async Task Shuffle()
{
Bitmap refreshBackImage = new Bitmap(getBack);
bCall.Enabled = false;
bRaise.Enabled = false;
bFold.Enabled = false;
bCheck.Enabled = false;
MaximizeBox = false;
MinimizeBox = false;
bool check = false;
horizontal = tbChips.Left - _settings.Width * 2 - 15;
vertical = pbTimer.Top - _settings.Height - (_settings.Height) / 7;
RNGCrypto random = new RNGCrypto();
for (i = ImgLocation.Length; i > 0; i--)
{
int j = random.Next(i);
string k = ImgLocation[j];
ImgLocation[j] = ImgLocation[i - 1];
ImgLocation[i - 1] = k;
}
for (i = 0; i < 17; i++)
{
Deck[i] = Image.FromFile(ImgLocation[i]);
string[] charsToRemove = { getCards, ".png", "\\" };
foreach (string c in charsToRemove)
{
ImgLocation[i] = ImgLocation[i].Replace(c, string.Empty);
}
Reserve[i] = int.Parse(ImgLocation[i]) - 1;
Holder[i] = new PictureBox
{
SizeMode = PictureBoxSizeMode.StretchImage,
Height = _settings.Height,
Width = _settings.Width
};
Controls.Add(Holder[i]);
Holder[i].Name = "pb" + i;
await Task.Delay(150);
#region Throwing Cards
SetPlayers(Player, i, ref check, 560, 470, refreshBackImage);
SetPlayers(Bot1, i, ref check, 15, 420, refreshBackImage);
SetPlayers(Bot2, i, ref check, 75, 65, refreshBackImage);
SetPlayers(Bot3, i, ref check, 590, 25, refreshBackImage);
SetPlayers(Bot4, i, ref check, 1115, 65, refreshBackImage);
SetPlayers(Bot5, i, ref check, 1160, 420, refreshBackImage);
if (i >= 12)
{
Holder[12].Tag = Reserve[12];
if (i > 12) Holder[13].Tag = Reserve[13];
if (i > 13) Holder[14].Tag = Reserve[14];
if (i > 14) Holder[15].Tag = Reserve[15];
if (i > 15)
{
Holder[16].Tag = Reserve[16];
}
if (!check)
{
horizontal = 410;
vertical = 265;
}
check = true;
if (Holder[i] != null)
{
Holder[i].Anchor = AnchorStyles.None;
Holder[i].Image = refreshBackImage;
//Holder[i].Image = Deck[i];
Holder[i].Location = new Point(horizontal, vertical);
horizontal += 110;
}
}
#endregion
Bot1 = (Bot)FoldedPlayer(Bot1);
Bot2 = (Bot)FoldedPlayer(Bot2);
Bot3 = (Bot)FoldedPlayer(Bot3);
Bot4 = (Bot)FoldedPlayer(Bot4);
Bot5 = (Bot)FoldedPlayer(Bot5);
if (i == 16)
{
if (!restart)
{
MaximizeBox = true;
MinimizeBox = true;
}
Turns();
}
}
Ending();
}
For things like animations, you might want the System.Windows.Forms.Timer component, which raises a periodic event.
You can configure the interval as well as temporarily disabling it entirely.
Note that after the delay, you'll be back to the top of the handler function... it doesn't automatically keep track of where you are in your sequence the way the await keyword automatically resumes at the next line. So you'll need some counter or such to let you know what step of the animation is coming next.
I'm not sure if you want to do the async, because it wont come back until it's complete. Meaning if you want something timed. Async will have some trouble providing this for you. Because you'll either have to wait for the response which may be an issue. Especially if its a game. Watch how the async functions in debug and you'll understand. An event trigger, or just a timed event will work much better because you'll have the control of when it triggers or how a long you wait for the event. This will get rid of your delay all together or it should.
In your case, a simple trigger event at the time, will display the throwing of cards, and once finished will continue on with your function. That's simple terms, you may have to do a few things like waiting until that trigger is finished. Either way there is a ton of information regarding events. Have a look before you go for async. Since it's forms you can do it however you please, if it for windows phone or other types of systems some require async only.
this should help:
https://msdn.microsoft.com/en-us/library/wkzf914z(v=vs.90).aspx

Thread start passed integer changes itself beyond what it should be [duplicate]

This question already has an answer here:
Thread alters passed Int, if start() is called separately
(1 answer)
Closed 7 years ago.
I have no idea what is going on in this. I'm trying to test thread safety of a class by spawning 100 threads to access it constantly, but it seems my anonymous method parameters are changing themselves to values they should never be and I'm confused as to why. As I have no idea what's going on, I'll just post all the functions involved in testing. Somehow I'm ending up with "Thread 98" getting the parameter "num = 100"... That shouldn't be possible and I have no idea what kind of hokey pokey is going on that is changing the integer. (in method "ThreadWriting(int num)" you'll see the point where I check for "num" to equal 100, where I put a break point to catch the offending thread in the act, and it breaks every time. Otherwise it throws an "IndexOutofRangeException" on the array "counts". I'm just trying to see if my threads are generally getting equal access to the class they're all trying to use at once.
public delegate void TempDel();
public TempDel InvokeTest;
public void TRTest3(Form1 sender)
{
InvokeTest = new TempDel(UpdateInvoke);
Thread t = new Thread(() => ConsoleUpdateTest(sender));
t.IsBackground = true;
t.Start();
POConsole.Instance.MaxLines = 20;
for(int i = 0; i < 100; i++)
{
Thread t2 = new Thread(() => ThreadWriting(i));
t2.IsBackground = true;
t2.Name = String.Format("Thread {0}", i);
t2.Start();
}
}
public ulong[] counts = new ulong[100];
public void ThreadWriting(int num)
{
if(num == 100)
{
bool stop = true;
}
while (true)
{
POConsole.Instance.WriteLine("Hello from Thread " + num);
counts[num]++;
}
}
public void ConsoleUpdateTest(Form1 sender)
{
while(true)
{
sender.Invoke(InvokeTest);
Thread.Sleep(5);
}
}
public void UpdateInvoke()
{
QuickTestBox.Text = POConsole.Instance.FullFeed;
}
All my threads are named, as you can see, and none of them receives the name "Thread 100" so I have no idea how one of the other threads could get passed a parameter of 100 or the parameter could be corrupted in some way.
Apparently my thread-safety checking isn't thread safe in some way?
This is a simple closure issue, you should not be using the for loop counter as a threading parameter issue, issue happens out here, for loop and thread execution do not run at same speed, so value of i can change for multiple threads:
for(int i = 0; i < 100; i++)
{
Thread t2 = new Thread(() => ThreadWriting(i));
t2.IsBackground = true;
t2.Name = String.Format("Thread {0}", i);
t2.Start();
}
Use following modification, create a local variable from loop counter
for(int i = 0; i < 100; i++)
{
int j = i;
Thread t2 = new Thread(() => ThreadWriting(j));
t2.IsBackground = true;
t2.Name = String.Format("Thread {0}", j);
t2.Start();
}

Run and stop a method for a minute

timer1= new System.Windows.Forms.Timer();
timer1.Interval =60000; // 1 min
timer1.Start();
MyMethodName();
timer1.Stop();
MyMethodName()
-has a for loop for 90,000 entries (and some validations inside that for loop).
for (int i = 0; i <= 90000; i++)
{
//validations go here
}
When the time in timer1 is done for a minute, i want to stop executing other entries in the for loop.
For example, if 45,000 entries are done in a minute, i want to stop executing the method ie. stop the method after a minute.
However the above timer code, executes till all the 90000 records are done looping inside the for loop, somehow the method doesn't run for a minute? Any help?
Two things. Firstly Your timer code is not actually connected to the running of MyMethodName. A timer is designed to run processes when the time has elapsed (and possibly at regular intervals depending on how it is set up.
Secondly and more to the point of your question to abort a loop you have to put code inside the loop. The key would be to have a stopwatch or similar start before your loop and then at the beginning of your loop check how much time has elapsed. If it is a minute or more then break;.
The key thing to note is that you will not stop exactly on a minute but you will finish the iteration of the loop that is running when the minute expires and then stop. This is usually what you want since stopping processing midway through something may cause nasty side effects.
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i =0; i<=90000; i++)
{
if (stopwatch.Elapsed>TimeSpan.FromSeconds(5))
break;
Console.WriteLine(i);
Thread.Sleep(1000);
}
Note that Thread.Sleep is there just because otherwise I get through all 90000 iterations too quickly. ;-)
So you would likely need a much different implementation. Consider this:
public class MyForm
{
private BackgroundWorker _worker;
public MyForm()
{
_worker = new BackgroundWorker();
_worker.DoWork += (s, args) =>
{
var timer = Stopwatch().StartNew();
do
{
// do something
} while (timer.ElapsedMilliseconds < 60000)
};
}
}
and then when you want to run it:
_worker.RunWorkerAsync();
However, you could make it even more robust. You could pass the time in like this:
_worker.RunWorkerAsync(60000);
and then in the DoWork handler, do this:
while (timer.ElapsedMilliseconds < (int)args.Argument)
Further, with the BackgroundWorker, you could support cancellation. Just set the WorkerSupportsCancellation flag to true and then in the condition do this:
while (timer.ElapsedMilliseconds < (int)args.Argument && !_worker.CancellationPending)
so, if necessary, you could do this:
_worker.CancelAsync();
Hmm, use a stopwatch instead
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
for(int i= 0; i <= 90000; i++)
{
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;
if(ts.Seconds >= 60)
break;
}
However the above timer code, executes till all the 90000 records are done looping inside the for loop, somehow the method doesn't run for a minute? Any help?
The timer will not raise events until you free up the UI thread, which won't occur until after the method completes fully.
If you want to prevent the method from running past a specific duration, you could handle it in your method directly:
MyMethodName(TimeSpan.FromMinutes(1));
Then, in your method:
void MyMethodName(TimeSpan maxRuntime)
{
DateTime expiration = DateTime.Now + maxRuntime;
for (int i = 0; i <= 90000; i++)
{
//validations go here
if (i % 100 == 0) // check every 100?
{
if (DateTime.Now > expiration)
break;
}
}
}
That being said, a better approach would be to push this into a background thread, and cancel as needed.
you can set a flag on in validations to see if it is done or not by hooking up an event handler to the Tick event in the Timer object
//in an area accessible to
//both elements
object readonly _lock = new object();
bool elapsed = false;
where your original code was
elapsed = false;
timer1= new System.Windows.Forms.Timer();
timer1.Interval =60000; // 1 min
timer1.Tick=((sender, everntArgs)=>
{
lock(_lock)
elapsed = true;
});
timer1.Start();
MyMethodName();
timer1.Stop();
Inside of MyMethodName
//inside the loop
for (int i = 0; i <= 90000; i++)
{
//validations go here
lock(_lock)
if(elapsed)
break;
}
If you use a CancellationTokenSource with the CancellationTokenSource(TimeSpan) constructor, it makes it easy to write a method that will cancel an action after a specified time.
You can write a method like so:
public static void RunTimedAction(Action<CancellationToken> action, TimeSpan timeout)
{
using (var cancellationTokenSource = new CancellationTokenSource(timeout))
action(cancellationTokenSource.Token);
}
And then you can write any action that takes a CancellationToken as a parameter, like this:
private void action(CancellationToken cancel)
{
int i;
for (i = 0; i < 1000000; ++i)
{
if (cancel.IsCancellationRequested)
break;
Thread.Sleep(10); // Simulate work.
}
Console.WriteLine("action() reached " + i);
}
Which you can use like this:
Console.WriteLine("Started at " + DateTime.Now);
RunTimedAction(action, TimeSpan.FromSeconds(10));
Console.WriteLine("Stopped at " + DateTime.Now);
Let's put this together into a complete demo program:
using System;
using System.Threading;
namespace Demo
{
class Program
{
void run()
{
Console.WriteLine("Started at " + DateTime.Now);
RunTimedAction(action, TimeSpan.FromSeconds(10));
Console.WriteLine("Stopped at " + DateTime.Now);
}
private void action(CancellationToken cancel)
{
int i;
for (i = 0; i < 1000000; ++i)
{
if (cancel.IsCancellationRequested)
break;
Thread.Sleep(10); // Simulate work.
}
Console.WriteLine("action() reached " + i);
}
public static void RunTimedAction(Action<CancellationToken> action, TimeSpan timeout)
{
using (var cancellationTokenSource = new CancellationTokenSource(timeout))
action(cancellationTokenSource.Token);
}
static void Main()
{
new Program().run();
}
}
}

Categories

Resources