I don't unrdersntat why with this code
static void Main(string[] args)
{
Console.WriteLine("START PROGRAMN-----------------------------------");
test();
Console.WriteLine("END PROGRAMN-----------------------------------");
Console.Read();
}
[ThreadStatic]
private static int i;
private static void test()
{
for (i = 0; i < 2; i++)
{
var bw = new BackgroundWorker();
// define the event handlers
bw.DoWork += (sender, args) =>
{
Console.WriteLine("START Thread-------------");
Console.WriteLine("Print:" + i);
};
bw.RunWorkerCompleted += (sender, args) =>
{
Console.WriteLine("END Thread-------------");
if (args.Error != null)
{
Console.WriteLine(args.Error.ToString());
}
};
bw.RunWorkerAsync(); // starts the
}
}
It will show this in console:
START PROGRAMN-----------------------------------
END PROGRAMN-----------------------------------
START Thread-------------
Print:0
END Thread-------------
START Thread-------------
Print:0
END Thread-------------
Why second print doesn't show print 1?
I think the first iteration is correct because I see print: 0 but in second why I don't see print: 1?
EDIT FOR ANSER
Without [ThreadStatic]
static void Main(string[] args)
{
Console.WriteLine("START PROGRAMN-----------------------------------");
test();
Console.WriteLine("END PROGRAMN-----------------------------------");
Console.Read();
}
[ThreadStatic]
private static int i;
private static void test()
{
for (i = 0; i < 2; i++)
{
var bw = new BackgroundWorker();
// define the event handlers
bw.DoWork += (sender, args) =>
{
Console.WriteLine("START Thread-------------");
Console.WriteLine("Print:" + i);
};
bw.RunWorkerCompleted += (sender, args) =>
{
Console.WriteLine("END Thread-------------");
if (args.Error != null)
{
Console.WriteLine(args.Error.ToString());
}
};
bw.RunWorkerAsync(); // starts the
}
}
It will show this in console:
START PROGRAMN-----------------------------------
END PROGRAMN-----------------------------------
START Thread-------------
Print:2
END Thread-------------
START Thread-------------
Print:2
END Thread-------------
Why first pirnt doesn't show print 0 and second print 1?
why show 2?
I think you do not really understand the ThreadStatic attribute here. It means that, by definition, Indicates that the value of a static field is unique for every thread. That means the value is unique for the Main Thread (where you are creating the BackgroundWorkers) and the BackgroundWorkers, that will always have the default value 0 for i.
Forget about that ThreadStatic you are not using this properly. It's not what you need in you case. The problem you are trying to bypass is because otherwise your result gets the latest value because the DoEvent is not started on the first thread that it already changed. You end up with a race condition. You do need to use arguments to have clear local instance of the variable. the easiest way is to change your code like so
for (int i = 0; i < 2; i++)
{
var bw = new BackgroundWorker();
// define the event handlers
bw.DoWork += (sender, args) =>
{
// get the argument
var value = args.Argument.ToString();
Console.WriteLine("START Thread-------------");
Console.WriteLine("Print:" + value);
};
bw.RunWorkerCompleted += (sender, args) =>
{
Console.WriteLine("END Thread-------------");
if (args.Error != null)
{
Console.WriteLine(args.Error.ToString());
}
};
bw.RunWorkerAsync(i); // starts the thread with arguments
}
Check your 'Console.WriteLine("Print:" + i);' inside the lambda.
The "Print:" + i is not evaluated and concatenated while inside the for loop. It will be present in your anonymous method and only will be concatenated when that method runs.
Because of your [ThreadStatic] attribute, int i is not shared between threads. "Each executing thread has a separate instance of the field, and independently sets and gets values for that field. If the field is accessed on a different thread, it will contain a different value."
int i will be instantiated and you get the int default value.
Related
I need to input specific keys (arrows.left and arrows.right) in my console application without blocking a loop.
Here's the code:
while (fuel>0) {
moveAndGenerate();
for (int i=0;i<road.GetLength(0); i++)
{
for (int j = 0; j < road.GetLength(1); j++)
{
Console.Write(string.Format("{0} ", road[i, j]));
}
Console.Write(Environment.NewLine + Environment.NewLine);
}
Console.WriteLine("Paliwo: "+ (fuel=fuel-5) + "%");
moveAndGenerate();
replaceArrays();
Thread.Sleep(1000);
Console.Clear();
}
it generates a simple game:
| :x|
| : |
|x: |
| :↑|
Within the loop as long as there's fuel. I want the arrow to move right/left without waiting for Console.ReadKey(). Is it possible?
As RB stated, you can setup a listener for the key press instead, and check if true if so they you reset the key press to null and move the car in that direction
Listen for key press in .NET console app
Another possible workaround is to use a BackgroundWorker to listen for input. This way you can handle both user input and the main code at the "same" time. It's similar to a separate thread.
You'll need to add using System.ComponentModel; to your program.
static BackgroundWorker backgroundWorker1 = new BackgroundWorker(); // Create the background worker
static string input = ""; // where the user command is stored
public static void Main()
{
// All the code preceding the main while loop is here
// Variable declarations etc.
//Setup a background worker
backgroundWorker1.DoWork += BackgroundWorker1_DoWork; // This tells the worker what to do once it starts working
backgroundWorker1.RunWorkerCompleted += BackgroundWorker1_RunWorkerCompleted; // This tells the worker what to do once its task is completed
backgroundWorker1.RunWorkerAsync(); // This starts the background worker
// Your main loop
while (fuel>0)
{
moveAndGenerate();
for (int i=0;i<road.GetLength(0); i++)
{
for (int j = 0; j < road.GetLength(1); j++)
{
Console.Write(string.Format("{0} ", road[i, j]));
}
Console.Write(Environment.NewLine + Environment.NewLine);
}
Console.WriteLine("Paliwo: "+ (fuel=fuel-5) + "%");
moveAndGenerate();
replaceArrays();
Thread.Sleep(1000);
Console.Clear();
}
// This is what the background worker will do in the background
private static void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (Console.KeyAvailable == false)
{
System.Threading.Thread.Sleep(100); // prevent the thread from eating too much CPU time
}
else
{
input = Console.In.ReadLine();
// Do stuff with input here or, since you can make it a static
// variable, do stuff with it in the while loop.
}
}
// This is what will happen when the worker completes reading
// a user input; since its task was completed, it will need to restart
private static void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs
{
if(!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync(); // restart the worker
}
}
}
TLDR;
Non-trivial memory leak, can be seen easily in Resharper. See minimal example below.
I'm seeing a memory leak in the following program but failing to see why.
The program sends pings to a number of hosts asynchronously and determines if at least one is ok. To do that, a method (SendPing()) that runs these async operations is repeatedly called which runs them in a background thread (it doesn't have to, but in the actual application SendPing() will be called by the main UI thread which shouldn't be blocked).
The task seems pretty trivial but I think the leak occurs due to the way I create lambdas inside the SendPing() method. The program can be changed to not use lambdas but I'm more interested in understanding what causes the leak here.
public class Program
{
static string[] hosts = { "www.google.com", "www.facebook.com" };
static void SendPing()
{
int numSucceeded = 0;
ManualResetEvent alldone = new ManualResetEvent(false);
ManualResetEvent[] handles = new ManualResetEvent[hosts.Length];
for (int i = 0; i < hosts.Length; i++)
handles[i] = new ManualResetEvent(false);
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (sender, args) =>
{
numSucceeded = 0;
Action<int, bool> onComplete = (hostIdx, succeeded) =>
{
if (succeeded) Interlocked.Increment(ref numSucceeded);
handles[hostIdx].Set();
};
for (int i = 0; i < hosts.Length; i++)
SendPing(i, onComplete);
ManualResetEvent.WaitAll(handles);
};
worker.RunWorkerCompleted += (sender, args) =>
{
Console.WriteLine("Succeeded " + numSucceeded);
BackgroundWorker bgw = sender as BackgroundWorker;
alldone.Set();
};
worker.RunWorkerAsync();
alldone.WaitOne();
worker.Dispose();
}
static void SendPing(int hostIdx, Action<int, bool> onComplete)
{
Ping pingSender = new Ping();
pingSender.PingCompleted += (sender, args) =>
{
bool succeeded = args.Error == null && !args.Cancelled && args.Reply != null && args.Reply.Status == IPStatus.Success;
onComplete(hostIdx, succeeded);
Ping p = sender as Ping;
p.Dispose();
};
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions(64, true);
pingSender.SendAsync(hosts[hostIdx], 2000, buffer, options, hostIdx);
}
private static void Main(string[] args)
{
for (int i = 0; i < 1000; i++)
{
Console.WriteLine("Send ping " + i);
SendPing();
}
}
}
Resharper shows the leaks are due to uncollected closure objects (c__DisplayClass...).
From what I understand, there shouldn't be a leak because there are no circular references (as far as I see) and therefore GC should take of the leaks. I also call Dispose to release the thread (bgw) + sockets (Ping object) promptly. (Even if I didn't GC will clean them up eventually, won't it?)
Suggested changes from comments
Remove event handles before Disposing
Dispose ManualResetEvent
But the leak is still there!
Changed program:
public class Program
{
static string[] hosts = { "www.google.com", "www.facebook.com" };
static void SendPing()
{
int numSucceeded = 0;
ManualResetEvent alldone = new ManualResetEvent(false);
BackgroundWorker worker = new BackgroundWorker();
DoWorkEventHandler doWork = (sender, args) =>
{
ManualResetEvent[] handles = new ManualResetEvent[hosts.Length];
for (int i = 0; i < hosts.Length; i++)
handles[i] = new ManualResetEvent(false);
numSucceeded = 0;
Action<int, bool> onComplete = (hostIdx, succeeded) =>
{
if (succeeded) Interlocked.Increment(ref numSucceeded);
handles[hostIdx].Set();
};
for (int i = 0; i < hosts.Length; i++)
SendPing(i, onComplete);
ManualResetEvent.WaitAll(handles);
foreach (var handle in handles)
handle.Close();
};
RunWorkerCompletedEventHandler completed = (sender, args) =>
{
Console.WriteLine("Succeeded " + numSucceeded);
BackgroundWorker bgw = sender as BackgroundWorker;
alldone.Set();
};
worker.DoWork += doWork;
worker.RunWorkerCompleted += completed;
worker.RunWorkerAsync();
alldone.WaitOne();
worker.DoWork -= doWork;
worker.RunWorkerCompleted -= completed;
worker.Dispose();
}
static void SendPing(int hostIdx, Action<int, bool> onComplete)
{
Ping pingSender = new Ping();
PingCompletedEventHandler completed = null;
completed = (sender, args) =>
{
bool succeeded = args.Error == null && !args.Cancelled && args.Reply != null && args.Reply.Status == IPStatus.Success;
onComplete(hostIdx, succeeded);
Ping p = sender as Ping;
p.PingCompleted -= completed;
p.Dispose();
};
pingSender.PingCompleted += completed;
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions(64, true);
pingSender.SendAsync(hosts[hostIdx], 2000, buffer, options, hostIdx);
}
private static void Main(string[] args)
{
for (int i = 0; i < 1000; i++)
{
Console.WriteLine("Send ping " + i);
SendPing();
}
}
}
There is no memory leak. dotMemory that you use analyzes the snapshots and indeed, in the context of one snapshot the auto-generated class created by the compiler for the completed event handler will still be in memory. Rewrite your main application like this:
private static void Main(string[] args)
{
for (int i = 0; i < 200; i++)
{
Console.WriteLine("Send ping " + i);
SendPing();
}
Console.WriteLine("All done");
Console.ReadLine();
}
Run the profiler, allow the application to reach the point where it outputs "All done", wait a few seconds and take a new snapshot. You will see there is no longer any memory leak.
It is worth mentioning that the class generated by the compiler for the PingCompleted event handler (that is c_DisplayClass6) will linger in memory after the method static void SendPing(int hostIdx, Action<int, bool> onComplete) exits. What happens there is that when pingSender.PingCompleted += (sender, args) =>... is executed the pingSender instance will take a reference to c_DisplayClass6. During the call to pingSender.SendAsync, the framework will retain a reference to pingSender in order to deal with running the async method and its completion. The async method you initiate by calling pingSender.SendAsync still runs when method SendPing exits. Because of that pingSender will survive a little while longer, hence c_DisplayClass6 will survive a little while longer too. However, after the pingSender.SendAsync operation completes, the framework will release its references to pingSender. At this point both pingSender and c_DisplayClass6 become garbage collectable and eventually the garbage collector will collect them. You can see this if you take a last snapshot like I was mentioning above. In that snapshot dotMemory will no longer detect a leak.
ManualResetEvent implements Dispose(). You are instantiating a number of ManualResetEvents and never calling dispose.
When an object implements dispose you need to call it. If you do not call it, there'll quite likely be memory leaks. You should use using statements, and try finally to dispose objects Simarly you should also have a using statement around Ping.
EDIT: This may be useful....
When should a ManualResetEvent be disposed?
EDIT: As stated here...
https://msdn.microsoft.com/en-us/library/498928w2(v=vs.110).aspx
When you create objects that include unmanaged resources, you must
explicitly release those resources when you finish using them in your
app.
EDIT: As stated here...
https://msdn.microsoft.com/en-us/library/system.threading.manualresetevent(v=vs.100).aspx
Dispose() Releases all resources used by the current instance of the
WaitHandle class. (Inherited from WaitHandle.)
The ManualResetEvent has unmanaged resources associated with it, which is fairly typical of most of the classes in the .NET Framework libraries which implements IDisposable.
EDIT: Try using this...
public class Program
{
static string[] hosts = { "www.google.com", "www.facebook.com" };
static void SendPing()
{
int numSucceeded = 0;
using (ManualResetEvent alldone = new ManualResetEvent(false))
{
BackgroundWorker worker = null;
ManualResetEvent[] handles = null;
try
{
worker = new BackgroundWorker();
DoWorkEventHandler doWork = (sender, args) =>
{
handles = new ManualResetEvent[hosts.Length];
for (int i = 0; i < hosts.Length; i++)
handles[i] = new ManualResetEvent(false);
numSucceeded = 0;
Action<int, bool> onComplete = (hostIdx, succeeded) =>
{
if (succeeded) Interlocked.Increment(ref numSucceeded);
handles[hostIdx].Set();
};
for (int i = 0; i < hosts.Length; i++)
SendPing(i, onComplete);
ManualResetEvent.WaitAll(handles);
foreach (var handle in handles)
handle.Close();
};
RunWorkerCompletedEventHandler completed = (sender, args) =>
{
Console.WriteLine("Succeeded " + numSucceeded);
BackgroundWorker bgw = sender as BackgroundWorker;
alldone.Set();
};
worker.DoWork += doWork;
worker.RunWorkerCompleted += completed;
worker.RunWorkerAsync();
alldone.WaitOne();
worker.DoWork -= doWork;
worker.RunWorkerCompleted -= completed;
}
finally
{
if (handles != null)
{
foreach (var handle in handles)
handle.Dispose();
}
if (worker != null)
worker.Dispose();
}
}
}
static void SendPing(int hostIdx, Action<int, bool> onComplete)
{
using (Ping pingSender = new Ping())
{
PingCompletedEventHandler completed = null;
completed = (sender, args) =>
{
bool succeeded = args.Error == null && !args.Cancelled && args.Reply != null && args.Reply.Status == IPStatus.Success;
onComplete(hostIdx, succeeded);
Ping p = sender as Ping;
p.PingCompleted -= completed;
p.Dispose();
};
pingSender.PingCompleted += completed;
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions(64, true);
pingSender.SendAsync(hosts[hostIdx], 2000, buffer, options, hostIdx);
}
}
private static void Main(string[] args)
{
for (int i = 0; i < 1000; i++)
{
Console.WriteLine("Send ping " + i);
SendPing();
}
}
}
Below is a function I have running in a while(true) loop in a thread running a Winforms GUI.
I have a button set to put text data into the inBuffer object. this always works, however when I place into the buffer object from a different thread, the data is detected, pulled, and printed out in the Console.out.WriteLine statement, however it never shows up in the Display (textBox) object
public void put()
{
string strDisplayMe = ModemKind.MainClass.inBuffer.MkRequest();
if (strDisplayMe != "")
{
Console.Out.WriteLine("FOUND SOMETHING IN BUFFER: " + strDisplayMe);
char[] DisplayMeArr = strDisplayMe.ToCharArray ();
for (int i = 0; i <= DisplayMeArr.Length -1; ++i)
{
this.display.Text += DisplayMeArr [i];
Thread.Sleep (100);
}
this.display.Text += '\n';
}
}
EDIT: this is a separate class from what is feeding it data through the static buffer objects
Only the main window thread can access/change controls... if you want update the UI from the thread that runs the loop, you need to sync the call with the main thread using the Control.Invoke method.
For instance...
public void put()
{
string strDisplayMe = ModemKind.MainClass.inBuffer.MkRequest();
if (strDisplayMe != string.Empty)
{
char[] DisplayMeArr = strDisplayMe.ToCharArray();
for (int i = 0; i <= DisplayMeArr.Length -1; ++i)
{
this.UpdateUI(() => { this.display.Text += DisplayMeArr[i]; });
Thread.Sleep(100);
}
this.UpdateUI(() => { this.display.Text += '\n'; });
}
}
private void UpdateUI(Action handler)
{
this.Invoke(handler);
}
You can use MethodInvoker to access TextBox from other thread then GUI thread. Make a method to access the TextBox using MethodInvoker. you are assigning text multiple times consider assigning it once for performance, and use StringBuilder for string concatenation.
public void put()
{
string strDisplayMe = ModemKind.MainClass.inBuffer.MkRequest();
if (strDisplayMe != "")
{
Console.Out.WriteLine("FOUND SOMETHING IN BUFFER: " + strDisplayMe);
char[] DisplayMeArr = strDisplayMe.ToCharArray ();
for (int i = 0; i <= DisplayMeArr.Length -1; ++i)
{
AssignToTextBox(this.display, this.display.Text + DisplayMeArr [i]);
Thread.Sleep (100);
}
AssignToTextBox(this.display, this.display.Text + '\n');
}
}
void AssignToTextBox(TextBox txtBox, string value)
{
if(txtBox.InvokeRequired)
{
txtBox.Invoke(new MethodInvoker(delegate { txtBox.text = value; }));
}
}
Edit You can use BeginInvoke instead of Invoke to call it asynchronously. Read more about the Invoke and BeginInvoke in this question.
void AssignToTextBox(TextBox txtBox, string value)
{
txtBox.BeginInvoke(new Action(()=>txtBox.Text = value ));
}
Alright, I'm trying to unit test NAudio against a wrapper I created for a recording session, here is the code that starts and stops a recording session ...
public void StartRecording(string claimNo, string ip_no, string ip_name)
{
if (this.IsRecording)
{
return;
}
this.Recordings.Add(new RecordingTrack(claimNo, ip_no, ip_name));
if (this.MicrophoneLevel == default(float))
{
this.MicrophoneLevel = .75f;
}
_aggregator.Reset();
_input = new WaveIn();
_input.WaveFormat = _waveFormat;
_input.DataAvailable += (s, args) =>
{
_writer.Write(args.Buffer, 0, args.BytesRecorded);
byte[] buffer = args.Buffer;
for (int index = 0; index < args.BytesRecorded; index += 2)
{
short sample = (short)((buffer[index + 1] << 8) | buffer[index + 0]);
float sample32 = sample / 32768f;
_aggregator.Add(sample32);
}
if (this.DataAvailable != null)
{
this.DataAvailable(s, args);
}
if (!this.IsRecording)
{
_writer.Close();
_writer.Dispose();
_writer = null;
}
};
_input.RecordingStopped += (s, args) =>
{
_input.Dispose();
_input = null;
if (this.RecordingStopped != null)
{
this.RecordingStopped(s, args);
}
};
_writer = new WaveFileWriter(this.CurrentRecording.FileName, _input.WaveFormat);
_input.StartRecording();
this.IsRecording = true;
}
public void StopRecording()
{
if (!this.IsRecording)
{
return;
}
this.CurrentRecording.Stop();
this.IsRecording = false;
_input.StopRecording();
}
... and below is my unit test. I'm using a ManualResetEvent to assert the success of the event being fired and it's declared like this ...
private ManualResetEvent _eventRaised = new ManualResetEvent(false);
... however, the issue is that the test below simply locks up and the event is never fired. Can you confirm that the issue is that the WaitOne is not allowing the event to fire because it's locking the same thread?
bool success = false;
_eventRaised.Reset();
var target = new RecordingSession();
target.StartRecording("1", "01", "Test Name");
target.RecordingStopped += (s, args) =>
{
success = (target.CurrentRecording.Duration.TotalSeconds > 4);
_eventRaised.Set();
};
Thread.Sleep(4000);
target.StopRecording();
_eventRaised.WaitOne();
Assert.IsTrue(success);
And if so, can you help me with this test? I need some enlightenment.
I've used the ManualResetEvent many times to test events on other classes and it's worked, but something is different here.
You'll never get an event because the default constructor of WaveIn uses windowed callbacks, and you are not running your unit test on a GUI thread. You should use WaveInEvent instead to work on a non-gui thread. In the very latest NAudio code an InvalidOperationException should be thrown to prevent you from making this mistake.
It is possible that the event is fired before you have connected to it if the _input member is working in its own thread. Hence, the manual reset event will never get set, causing it to wait forever/lock up your unit test.
So perhaps try re-order your definition to:
target.RecordingStopped += (s, args) =>
{
success = (target.CurrentRecording.Duration.TotalSeconds > 4);
_eventRaised.Set();
};
target.StartRecording("1", "01", "Test Name");
Is there any possible way to access the field - str in the Class Program and the variable num - in the main function?
class Program
{
string str = "This is a string";
static void Main(string[] args)
{
int num = 100;
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
var timer = new System.Timers.Timer(10000);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
for (int i = 0; i < 20; i++)
{
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " " + "current I is " + i.ToString());
Thread.Sleep(1000);
}
Console.ReadLine();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Debug.WriteLine(str);
Debug.WriteLine(num);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " current is timer");
//throw new NotImplementedException();
}
}
Best Regards,
The field just needs to be made static.
static string str = "This is a string";
To access num you need to use a lambda expression.
timer.Elapsed += new ElapsedEventHandler((s, e) =>
{
Debug.WriteLine(str);
Debug.WriteLine(num);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " current is timer");
});
You can also use an anonymous method.
timer.Elapsed += new ElapsedEventHandler(delegate(object sender, ElapsedEventArgs e)
{
Debug.WriteLine(str);
Debug.WriteLine(num);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " current is timer");
});
There is one more option. The System.Threading.Timer class allows you to pass a state object.
var timer = new System.Threading.Timer((state) =>
{
Debug.WriteLine(str);
Debug.WriteLine(state);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " current is timer");
}, num, 10000, 10000);
str should be accessible directly if you change it to static as its implemented now since it is at class level. Num is internal to main and so cannot be accessed unless you pass a reference to it. You can move it external to main, or if its supported in ElapsedEventArgs pass a reference to it and retrieve it that way.