There is a console application that simulates router functionality (packet swithcing and so on). I made a simple Windows Form that should show how much each router's socket is used. Each socket has different capacity and each Form "connected" to socket should show how much capacity there is still available.
My code so far:
static void Main(string[] args)
{
//get number of router's sockets
args = Environment.GetCommandLineArgs();
int socketnumber = Convert.ToInt32(args[2]);
//get sockets' capacity
int[] array = new int[socketnumber];
for (int i = 0; i < socketnumber; i++)
{
array[i] = Convert.ToInt32(args[3 + i]);
}
Now, LRM is a WinForm that shows each socket's (or, more accurately, link's attached to socket) status, so I initialize it and give it parameters.
LRM[] lrm = new LRM[socketnumber];
for (int i = 0; i < socketnumber; i++)
{
lrm[i] = new LRM();
lrm[i].Show();
a++;
}
for (int i = 0; i < socketnumber; i++)
{
Console.WriteLine(array[i]);
lrm[i].capacity = array[i];
lrm[i].available = array[i];
lrm[i].WriteCapacity(lrm[i].capacity);
lrm[i].WriteAvailable(lrm[i].available);
}
WriteCapacity and WriteAvailable are methods that are invoked by router to update values on LRM, like that:
public void WriteAvailable(int ava)
{
MethodInvoker mi = delegate ()
{
textBox2.Text = ava.ToString();
};
Invoke(mi);
}
Now, current problems I have:
1) Running multiple windows forms from console AND maintaining their functionality (all of them simultaneously), when number of windows forms varies (is set by command line argument)
2) Updating LRM values. When using show() method it just displays the form, it does not give it any values, and soon after form stops to respond, giving windows error. When using Application.Run() method, one form runs nicely, but neither other LRMs nor router's console works.
I appreciate Alexander Petrov's answer, but I found a way to solve my problem.
I tried Thread approach. First I made most of my variables static:
static int[] array;
static LRM[] lrm;
static int port;
then I made method that will be acting as thread starting method
private static void startLRM(int i)
{
Console.WriteLine(i);
lrm[i].Text = "LRM R" + ((port / 10) - 120).ToString() + " S" + a.ToString();
a++;
Console.WriteLine(array[i]);
lrm[i].capacity = array[i];
lrm[i].available = array[i];
lrm[i].WriteCapacity(lrm[i].capacity);
lrm[i].WriteAvailable(lrm[i].available);
lrm[i].ShowDialog();
}
Then, in Main() method, I allocated memory for link resource managers,and in for loop I made as many LRMs as were needed.
lrm = new LRM[socketnumber];
for (int i = 0; i < socketnumber; i++)
{
lrm[i] = new LRM();
Thread thread = new Thread(() => startLRM(i));
thread.Start();
Thread.Sleep(150);
}
Sleeping was actually necessary, because for unknown reasons I got errors when it was not there.
Finally, I get what I needed - a console application, which shows what is happening, and few windows forms that shows in nice manner some values.
Related
I have a CustomControl called PlaylistView. It displays elements in a playlist with name and thumbnail. The method DisplayPlaylist ensures that a thread is started, in which the individual elements are added one by one and the thumbnails (30th frame) are read out:
public void DisplayPlaylist(Playlist playlist)
{
Thread thread = new Thread(() => DisplayElements(playlist));
thread.Start();
}
private void DisplayElements(Playlist playlist)
{
for (int i = 0; i < playlist.elements.Count; i++)
DisplayElement(playlist.elements[i], i);
}
private void DisplayElement(IPlayable element, int index)
{
VideoSelect videoSelect = null;
if (element is Audio)
//
else if (element is Video)
videoSelect = new VideoSelect(index, element.name, GetThumbnail(element.path, SystemData.thumbnailFrame));
videoSelect.Location = GetElementsPosition(index);
panel_List.BeginInvoke(new Action(() =>
{
panel_List.Controls.Add(videoSelect);
}));
}
private Bitmap GetThumbnail(string path, int frame)
{
VideoFileReader reader = new VideoFileReader();
try
{
reader.Open(path);
for (int i = 1; i < frame; i++)
reader.ReadVideoFrame();
return reader.ReadVideoFrame();
}
catch
{
return null;
}
}
But there is a problem.
It is much too slow (about 10 elements/sec). With a playlist length of 614, you would have to wait more than a minute until all are displayed. Each time you change the playlist, such as adding or deleting an item, the procedure starts with the new item. Adding 2 or more will make it even more complicated.
I now had the approach to use multiple threads and the number of threads used for this to be specified by the user (1 to max 10). The implementation in the code currently looks like this (only changed parts compared to the previously posted code)
public void DisplayPlaylist(Playlist playlist)
{
for (int i = 0; i < SystemData.usedDisplayingThreads; i++)
{
Thread thread = new Thread(() => DisplayElements(playlist, i));
thread.Start();
}
}
private void DisplayElements(Playlist playlist, int startIndex)
{
for (int i = startIndex; i < playlist.elements.Count; i += SystemData.usedDisplayingThreads)
DisplayElement(playlist.elements[i], i);
}
The problem is that now very often null is returned by the GetThumbnail function, so an error occurs. In addition, a System.AccessViolationException is often thrown out.
In my opinion, the reason for this is the presence of multiple, simultaneously active VideoFileReaders. However, I do not know what exactly triggers the problem so I cannot present any solution. Maybe you know what the actual trigger is and how to fix the problem or maybe you also know other methods for speed improvement, which maybe even more elegant.
I would start with logging what exception is raised in GetThumbnail method. Your code hides it and returns null. Change to catch (Exception exc), write exception details in log or at least evaluate in debugger. That can give a hint.
Also I'm pretty sure your VideoFileReader instances are IDisposable, so you have to dispose them by invoking reader.Close(). Maybe previous instances were not disposed and you are trying to open same file multiple times.
Update: video frame has to be disposed as well. Probably you will need to do a copy of bitmap if it is referenced with reader and prevents disposion.
I'm running into a sync issue involving reporting progress inside of a Parallel.ForEach. I recreated a simplified version of the problem in a Console App. The example actually only uses one item in the list. Here's the code:
class Program
{
static void Main(string[] args)
{
int tracker = 0;
Parallel.ForEach(Enumerable.Range(1, 1), (item) =>
{
var progress = new Progress<int>((p) =>
{
tracker = p;
Console.WriteLine(String.Format("{0}", p));
});
Test(progress);
});
Console.WriteLine("The last value is: {0}", tracker);
Console.ReadKey();
}
static void Test(IProgress<int> progress)
{
for (int i = 0; i < 20; i++)
{
progress.Report(i);
}
}
}
As you can see, the line I expect to see last isn't output last and doesn't contain 20. But if I remove progress reporting and just write to output in the for loop like this:
class Program
{
static void Main(string[] args)
{
int tracker = 0;
Parallel.ForEach(Enumerable.Range(1, 1), (item) =>
{
tracker = Test();
});
Console.WriteLine("The last value is: {0}", tracker);
Console.ReadKey();
}
static int Test()
{
int i;
for ( i = 0; i < 20; i++)
{
Console.WriteLine(i.ToString());
}
return i;
}
}
it behaves like I expect. As far as I know, Parallel.ForEach creates a Task for each in item in the list and IProgress captures the context in which it's created on. Given it's a console app I didn't think that would matter. Help please!
The explanation is pretty much exactly what's written in the docs:
Any handler provided to the constructor or event handlers registered with the ProgressChanged event are invoked through a SynchronizationContext instance captured when the instance is constructed. If there is no current SynchronizationContext at the time of construction, the callbacks will be invoked on the ThreadPool.
By using Progress<T>.Report you're effectively queueing 20 tasks on the thread pool. There's no guarantee as to what order they're executed in.
I am making a simple wpf application. It has a button and a textbox and when you click the button it should update the textbox the whole time(see code). I have 3 problems:
It doesn't update the textbox in the loop.
When I click the button It is stuck and I can't close the application(only with taskmanager and stop debugging).
If i leave the textbox stuck and do not close it. After a minute or so I get this error: ContextSwitchDeadlock occurred with the break mode screen.
I have tried to solve the problem by searching on the internet but I didn't succeed. I hope you guys are able to solve it:). And the code is here:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Play_Click(object sender, RoutedEventArgs e)
{
int x = RandomNumber();
}
private string TextboxData;
private int RandomNumber()
{
int x = 0;
int i = 0;
Random rng = new Random();
do
{
x = rng.Next(1, 1000000);
i++;
TextboxData += "\r\nAl zo vaak :O" + i; //the rng loop
textBox.Text = TextboxData;
}
while (x != 1);
TextboxData += "\r\nHij heeft zo vaak geprobeerd 1 te halen " + i;
textBox.Text = TextboxData + Environment.NewLine;
return x;
}
}
The problem is that all your actions are made in main GUI thread.
That means that your program can't redraw interface because it's busy executing code in loop.
In order to achieve desired results you need to execute your loop asynchronous. But we must keep in mind that GUI should be updated only from GUI thread( it's framework requirement).
Due to quick calculations the texbox will be updated too often. You may consider using Thread.Sleep(100).
Here's solution:
private async void Play_Click(object sender, RoutedEventArgs e)
{
int x = await RandomNumber();
}
private async Task<int> RandomNumber()
{
int x = 0;
int i = 0;
string text = string.Empty;
Random rng = new Random();
// This will start work in background. Leaving GUI thread to it's own tasks.
await Task.Factory.StartNew(() =>
{
do
{
x = rng.Next(1, 1000000);
i++;
text = "\r\nAl zo vaak :O" + i.ToString(); //the rng loop
// This will invoke textbox update in GUI thread satisfying update requirement.
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input,
new Action(() => { textBox.AppendText(text); }));
// We will make it slower in order to see updates at adequate rate.
Thread.Sleep(100);
}
while (x != 1);
});
// thanks to await we will have this code executed after we found our x==1.
text = "\r\nHij heeft zo vaak geprobeerd 1 te halen " + i;
textBox.AppendText(text);
return x;
}
Don't forget to add following usings:
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
EDIT: I don't know why you want to have return value from RandomNumber() (it will always be 1. so it's pontless). But to handle that correctly we need to add async to our signatures in order to use await so we could get a value, execute code after awaited block and return result.
It's a pretty complicated topic, which I will only mention here in order to have correct solution. If you're interested - google '.net async await'. But I suggest to leave it for future :)
Also, I removed TextBoxData field and replaced it with local variable and used textbox.AppendText() as #KevinKal suggested.
How can I run the code below in LinqPad as C# Program Thank you...
class ThreadTest
{
static void Main()
{
Thread t = new Thread (WriteY); // Kick off a new thread
t.Start(); // running WriteY()
// Simultaneously, do something on the main thread.
for (int i = 0; i < 1000; i++) Console.Write ("x");
}
static void WriteY()
{
for (int i = 0; i < 1000; i++) Console.Write ("y");
}
}
Result Expected
xxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
So far I came up with
static void Main()
{
Thread t = new Thread (ThreadTest.WriteY); // Kick off a new thread
t.Start(); // running WriteY()
// Simultaneously, do something on the main thread.
for (int i = 0; i < 1000; i++) Console.Write ("x");
}
class ThreadTest
{
public static void WriteY()
{
for (int i = 0; i < 1000; i++) Console.Write ("y");
}
}
Actual Result
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy...
As seen on Result Expected it should be mixed X and Y.
Unfortunately Actual Result is 1000 times X and 1000 times Y
UPDATE
This sample - along with all the others in the concurrency chapters of C# 5 in a Nutshell are downloadable as a LINQPad sample library. Go to LINQPad's samples TreeView and click 'Download/Import more samples' and choose the first listing. – Joe Albahari
Thread switching is by nature non-deterministic. I can run your program multiple times and get varying results.
If you want the switching to be more evident, add some pauses:
static void Main()
{
Thread t = new Thread (ThreadTest.WriteY); // Kick off a new thread
t.Start(); // running WriteY()
// Simultaneously, do something on the main thread.
for (int i = 0; i < 1000; i++)
{
Console.Write ("x");
Thread.Sleep(1);
}
}
class ThreadTest
{
public static void WriteY()
{
for (int i = 0; i < 1000; i++)
{
Console.Write ("y");
Thread.Sleep(1);
}
}
}
I cannot explain why this works, but changing to using Dump() seems to make it behave like the OP wants with the x's and y's "mixed" with every run (although with newlines between every output):
void Main()
{
Thread t = new Thread (ThreadTest.WriteY); // Kick off a new thread
t.Start(); // running WriteY()
// Simultaneously, do something on the main thread.
for (int i = 0; i < 1000; i++) "x".Dump();
}
class ThreadTest
{
public static void WriteY()
{
for (int i = 0; i < 1000; i++) "y".Dump();
}
}
From the LinqPAD documentation:
LINQPad's Dump command feeds the output into an XHTML stream which it
displays using an embedded web browser (you can see this by
right-clicking a query result and choosing 'View Source'. The
transformation into XHTML is done entirely using LINQ to XML, as one
big LINQ query! The deferred expansion of results works via
JavaScript, which means the XHTML is fully prepopulated after a query
finishes executing. The lambda window populates using a custom
expression tree visitor (simply calling ToString on an expression tree
is no good because it puts the entire output on one line).
I also know that LinqPAD overrides the default Console.WriteLine behavior, so perhaps that has something to do with it.
I am trying to create a simple Network Tool to ping all possible IPs on your local subnet and provide a list of such IPs in a DataGridView. I am new to having to consider threading which is a good thing to come across as a budding programmer. Sorry, but you are probably going to have to do some explaining to me, but in my mind this should work. Before I tried putting it in a backgroundworker thread, the application would just hang and give me a "Not Responding".
thanks ahead of time.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
count = 0;
for (int j = 1; j < 255; j++)
for (int i = 1; i < 255; i++)
{
Ping ping = new Ping();
PingReply pingreply = ping.Send(IPAddress.Parse(locip[0] + "." + locip[1] + "." + j + "." + i));
if (pingreply.Status == IPStatus.Success)
{
status = "o";
repAddress = pingreply.Address.ToString(); ;
repRoundtrip = pingreply.RoundtripTime.ToString();
repTTL = pingreply.Options.Ttl.ToString();
repBuffer = pingreply.Buffer.Length.ToString();
string[] lineBuffer = { status, repAddress, repRoundtrip, repTTL, repBuffer };
ipList.Rows.Add(lineBuffer);
count += 1;
progressBar.Value += 1;
}
}
}
You cannot access directly the progressBar1 (or any other UI element) from the backgroundWorker1 "DoWork" event, you have to use the backgroundWorker1.ProgressChanged method and handle ProgressChanged event:
// instead of progressBar.Value += 1
// use the following
const int total = 254 * 254;
backgroundWorker1.ReportProgress(count / total);
WorkerReportsProgress should be assigned to true
and the event of ProgressChanged to the following method
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// assuming the Minimum = 0 and Maximum = 100 on progressBar
progressBar.Value = e.ProgressPercentage;
}
Part of the problem is that you are directly accessing a UI element from your background thread. The field progressBar is presumably a UI progress bar control and can only be safely accessed from the UI thread. You must use a call to .Invoke to set this value from the UI thread.
progressBar.Invoke(new MethodInvoker(UpdateProgressBarbyOne));
...
private void UpdateProgressBarByOne() {
progressBar.Value += 1;
}
Ah I love threading. It makes programs so much more interesting...
So as I started off learning about how to make responsive applications I came across the function: Application.DoEvents()
(http://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents.aspx)
What this does is causes your form to process some of the window events it's receiving. I think that your code could change to include a call after each ping request...
i.e. within the on click event handler
count = 0;
for (int j = 1; j < 255; j++)
for (int i = 1; i < 255; i++)
{
Ping ping = new Ping();
PingReply pingreply = ping.Send(IPAddress.Parse(locip[0] + "." + locip[1] + "." + j + "." + i));
if (pingreply.Status == IPStatus.Success)
{
status = "o";
repAddress = pingreply.Address.ToString(); ;
repRoundtrip = pingreply.RoundtripTime.ToString();
repTTL = pingreply.Options.Ttl.ToString();
repBuffer = pingreply.Buffer.Length.ToString();
string[] lineBuffer = { status, repAddress, repRoundtrip, repTTL, repBuffer };
ipList.Rows.Add(lineBuffer);
count += 1;
progressBar.Value += 1;
}
Application.DoEvents(); //but not too often.
}
Now this was back in the pre dot net days and it's survived till now however, it's not something that you should take lightly. If you click another button on the form it will start off another thread that will attempt to execute and if you're not careful cause thread exceptions on your form. Some developers will tell you don't use this but since your starting off I'd say give it a shot :)
I might not use this method depending on the application. Instead what I would do it actually do is to create several processing "trains"; one for each cpu core that the system had. I'd add the ips to be scanned to a queue object and then I would start up 2 to 4 instances of threads (http://msdn.microsoft.com/en-us/library/system.threading.thread.aspx) each of which taking an item off the queue in turn, process the information (i.e. do the ping logic) and put the result on another queue; and output queue. Every time a train would finish an item for work it would raise an event at the other end of which there would be a handler in the form. Using the Invoke to make thread safe calls (http://msdn.microsoft.com/en-us/library/ms171728.aspx) on my form I would update the UI's information accordingly.
Threading is fun dude :) over time you can find that you can use MSMQ to make a system that uses the multicores of other computers to do jobs such as image processing (or something with pa....... ;)