C# have a seperate draw thread for the application.

Page 2 - Seeking answers? Join the AnandTech community: where nearly half-a-million members share solutions and discuss the latest tech.

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
I have tried using BeginInvoke instead of invoke which kind of works.

The good news is that the iteration loop finishes as fast as ever. But then the program stays handling all the updates for a while.

Also memory usage goes through the roof with BeginInvoke. I have been unable to use EndInvoke or understand and utilize all the online examples I found so far.

Now there just needs to be a async way to push to the display and draw, but allow skipping data so only the latest value is displayed like a video with dropped frames.
 

Cogman

Lifer
Sep 19, 2000
10,277
125
106
look, your problem is that you are trying to draw the results for each iteration. DON'T DO THAT. If you want speed and responsiveness, drop invoke all together and go with a class variable to take care of the state of the thread. If you try and render every iteration, you are going to slug your program. Screen rendering IS SLOW.

When you use BeginInvoke, you are essentially just spawning a new thread for each iteration (1mb is generally used per thread). Drop invoke all together, it is destroying your performance.
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
Rendering to the screen is meaningless as are the iterations. I don't need any of it in my acual code, I just need to render anything, even one instance, without slowing down my code.

Enver if I render only once at value 1000000 that 1 render can take more time then the entire loop and kill performance, just 1. I need a way to make all rendering asyncronus so the code can continue.

In my real code I am going through live data in real time, lets say network data and I need to show number of packets seen in second increments. Just 1 render kills my speed.

Thanks again,
 

Cogman

Lifer
Sep 19, 2000
10,277
125
106
Rendering to the screen is meaningless as are the iterations. I don't need any of it in my acual code, I just need to render anything, even one instance, without slowing down my code.

Enver if I render only once at value 1000000 that 1 render can take more time then the entire loop and kill performance, just 1. I need a way to make all rendering asyncronus so the code can continue.

In my real code I am going through live data in real time, lets say network data and I need to show number of packets seen in second increments. Just 1 render kills my speed.

Thanks again,

What you are doing, right now, by using the invoke is creating a thread and then making it wait until rendering is done. You don't have one thread doing rendering and one thread doing computations, you have one thread doing rendering and one thread that waits on the one thread to do rendering.

Remove the Invoke. Use shared memory to pass data rather then calling an invoke. I don't know how I could be clearer. Invoke blocks one threads execution and waits for the next to complete. That means that your computations thread is waiting for the rendering thread to complete.

You need a lazy model. Data gets stored in memory (not in a rendered element) One thread renders the data as fast as possible while the other does computations as fast as possible. The thread doing the rendering wont always display exactly what the computations thread is doing, but that doesn't matter, rendering is more for the user and less about accurate computations.

I realize that rendering is meaningless in your example, and what I am saying is right now you are rendering EVERYTHING, not just something. That slows things down tremendously.
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
I took out the Invoke, however the invoke itself does not slow down the application nearly as much if I don't do any painting but still slower.

I made my datagrid virtual and added a form timer as mentioned earlier. So I update the table only on timer events which then is drawn to the table exactly as mentioned earlier.

The timer iterates every 10 ms now and it is much faster than before, but still slower then if no painting is involved. I am also trying to paint differently and have the grid pull the data. Have the timer invalidate the cell and then on the next cellvalueneeded have it pull the value, which should be fater then updates from the data table however it does not work yet.

This also puts me with a timer. Interestingly enough changing the timer from 10 to 100 does nothing to performance. I would expect it to become 10 times faster. Also, your method with the Application.DoEvents() loop works pretty much at the same speed as the timer but slightly faster. Both timers take about .95 seconds for 100 million iterations but the application.doevents takes about .85 seconds.
I do find it interesting that the loop is faster, but DoEvents lets other threads run and only continues when it is started next. However does that mean that the main thread cannot continue when the while loop is going, in the case that I have 2 worker threads? Then again, I can monitor both threads for activity.

It is much fasted now using very early suggestions. I am still trying to make it better and smoother.

Thanks again.
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
Thanks, I can't run the application I have VS 2008 at work and it does not want to open it. I will try it tonight.
 

Cogman

Lifer
Sep 19, 2000
10,277
125
106
Thanks, I can't run the application I have VS 2008 at work and it does not want to open it. I will try it tonight.

I didn't do any .net 4.0y things in there, so just start a new project and import the necessary files.
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
Still not working, I don't see anyhting in the files other than the basic constructor.

How does a WPF application differ from forms?
 

Cogman

Lifer
Sep 19, 2000
10,277
125
106
Still not working, I don't see anyhting in the files other than the basic constructor.

How does a WPF application differ from forms?

It is a forms application (unless I got the wrong one.. Just a sec.)
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
Thanks, this one works fine. A couple questions though. In the fast thread you don't have Application.DoEvents and I tried taking it out of my 100 mil loop and it became really slow so DoEvents gives other threads or events a chance to run. Is it always safe for non critical events or threads?

For the medium timer you have BeginInvoke with the Invoker variable. Is setting the invoker the same as a EndInvoke?

I have also been reading about a fire and forget delegate. Is that the same as BeginInvoke or is it something else and is it faster?


My mistake, without the DoEvents it is slower but only slightly.
 
Last edited:

Cogman

Lifer
Sep 19, 2000
10,277
125
106
Thanks, this one works fine. A couple questions though. In the fast thread you don't have Application.DoEvents and I tried taking it out of my 100 mil loop and it became really slow so DoEvents gives other threads or events a chance to run. Is it always safe for non critical events or threads?

For the medium timer you have BeginInvoke with the Invoker variable. Is setting the invoker the same as a EndInvoke?

I have also been reading about a fire and forget delegate. Is that the same as BeginInvoke or is it something else and is it faster?

The lack of the doevents in the faster code was by mistake. Throw it in there and you have what I meant to present (I took it out because I was playing with some things).

The invoker variable is simply there to make sure that you don't have a mile long line of invokes to the main thread. It makes it so that updating appears to go smoothly.

Fire and forget delegates are the ones where you would do something like
BeginInvoke(new delegateVariable(functionName));
where you are making multiple new variables to each delegate function.

BeginInvoke simply returns control back to the thread that called it while it goes off and does its work. Rather then calling an invoke every time in the medium thread, I only call it when the last evoke finishes firing. This allows the thread to go as fast as needed without having to worry that the content isn't being updated properly.

You should note, this isn't the absolute fastest threaded code I can write, rather, this is just an example of how threaded code should be written. To make multiple threads run faster, you generally want locking to be a sort of "last resort" thing (not what I'm doing here). The contention for the lock here will significantly slow things down. If I was going to make this faster, I would have a local variable in the thread, then have that thread attempt to use the lock, if it can't, manipulated the local variable some more until it can obtain the lock, Then update the data protected by the lock with the information from the local variable. This leads to pretty fast threading code because it significantly reduces locking contention. (I don't know how to try locks, so to speak, in c#. In c++ it was a simple TryEnterCriticalSection(CS)).
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
I didn't even notice that the Invoker.IsCompleted at first. I removed the first modulo check and noticed that performance remains the same. The updating itself is the bottleneck and it is great to be able to have the worker let it finish before updating again.

I also have no idea how to test a lock. I will see what I can do, but for now I should not need to do to much locking.

Thanks again.
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
Hi, I was busy so I could not update in a while.

My next step is to load a second form window to change values of the primary program but without blocking the main program.
Here is my solution so far VS 2010 file: http://www.multiupload.com/867Y2HBGI3

The example I was using was from here: http://www.homeandlearn.co.uk/csharp/csharp_s13p1.html

One thing that is very important is that I can always press button1. With the example, the show command can result in multiple windows and if the window blocks, as with a message box, button1 cannot be pressed. The ShowDialog() option always blocks the main form.

In my code I start the second form as it's own application in a new form. And when the form exits, it invokes the primary window to change the text box.

It is working almost perfectly.
the problem happens if I press button2 a second time while the second form is open. Since the second form can be minimized or hidden behind another window, I want pressing button12 a second time to show the second form or bring it to the front. I get a cross-threading error, which surprises me as I am using an invoke to the second thread. And since the entire second application exists in a different thread, I don't understand why any call to form2 does not run in thread2 automatically.

I still cannot get second form to become the front. Any idea what I am doing wrong and why?

Something else that would be nice is that I would like to control where the second window opens, I would like i to be close to the main form, but not blocking ir or at least not button1. And if the form is re-show as above, it should also be moved close to the same form.

I have been going though this: http://msdn.microsoft.com/query/dev...WORK,VERSION=V4.0");k(DevLang-CSHARP)&rd=true

to try to use background worker threads, but I don't understand how the basic examples can work and how they can make safe calls between threads?

Thanks again,
elkinm
 

Mark R

Diamond Member
Oct 9, 1999
8,513
14
81
Edit: Original post was talking BS.

The reason your BeginInvoke call is failing is you are trying to invoke a secondForm method on Form1's thread.

In Form1, you call BeginInvoke (secondForm.showformdelegate). However, you haven't explicity specified which object to call BeginInvoke on. As BeginInvoke is a member of Form1, it gets executed as:
Form1.BeginInvoke (blah...) which forces the execution to run in Form 1's thread.

It works fine if you call it as secondForm.Invoke (secondForm.showformdelegate).


Personally, I prefer to put all your forms into a single thread. That way, there is no cross-thread mayhem to deal with.
Then put your workers into separate threads.
See Link
 
Last edited:

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
You're trying to spawn new threads containing multiple application loops and forms. While this might work, I'm not sure it's how you're meant to do it. In particular, your accessing the 'Application' object from 2 separate threads. That's asking for trouble.

Your cross threading error comes from the fact that your 'Application' object (which is what does the invoking) was originally created on your original thread. But your second form is running in a different thread, and you're trying to use the same 'Application' object to manage your new form.

The simplest way to make your program work is to get rid of 'Application.Run()' on the second form, and replace it with 'secondform.ShowDialog()'. ShowDialog will create it's own message loop for the thread (blocking the main message loop if there is one). In this case, there is no already running message loop on your secondform thread, so nothing will block.
Code:
private void StartForm2()
        {
            TextString = txtChangeCase.Text;
            secondForm = new Form2();
            //Application.Run(secondForm);
            secondForm.ShowDialog();
            if (txtChangeCase.Text != TextString)
            {
                BeginInvoke(updatedtextdelegate, null);
            }
        }

Personally, I prefer to put all your forms into a single thread. That way, there is no cross-thread mayhem to deal with.
Then put your workers into separate threads.
See Link

I just tried the showDialog option and it worked. This surprised me is that before it just the form appeared and disappeared instantly in another thread, or with a regular showdialog with would block the first form and button1.

However, I still cannot get form2 to go to the front if it is already open. I get an exception caused by the invalid invocation. I also cannot get it to work with show because of the threading error.

My end goal is to have a way to have one main thread run all the visual items, I just don't know how to do it.

I don't know the best way to do what I need, which is what this post is about. Here are the list of requirements I have.
1. Button1 can be pressed at any time. (is there a way to protect it such the compiler will throw an error if some condition can block the button?)
2. Form2 or the request form cannot slow down or crash the main app. (henche the second thread and app)
2 It would be nice if form2 did what it was supposed to, or update the test in this case.

Thanks again.
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
I am going through your code. The only problem with it that when a message box pops up either from not selecting an option or if the worker is already running, button1 is blocked. In this case with a worker, both button1 and the stop work button should be pressable at all times.
I should be able to pull the fire-alarm or stop the worker (which may be causing the fire).

Thanks again.

EDIT, since the message box is the big problem at the moment can it be launched in a new thread that is always at the top but without interfering with the main program.
 
Last edited:

Mark R

Diamond Member
Oct 9, 1999
8,513
14
81
EDIT, since the message box is the big problem at the moment can it be launched in a new thread that is always at the top but without interfering with the main program.

First: I've edited my post because I was talking BS. Your code was almost right, but I didn't see the problem initially. Just that the idea of having multiple message-loops seemed a very strange way to solve the problem (but I can confirm that it does work). You need to fix your Invoke command (as I describe in the edited post).

The thing about a MessageBox is that it blocks the thread that it is running in. It is designed this way, so that the user can be informed of a problem that is stopping the program from continuing.

If you need an alert that doesn't block the thread - then you can just spawn a new form. Make a form that looks like a message box. Then just 'Show' it. It will run quite happily in the same thread as your main Form. This avoids any complicated cross-thread communication.

You could run a messagebox in another thread - but why add the complexity of another thread, when you can just use another form with an OK button and a Label in it.
1. Button1 can be pressed at any time. (is there a way to protect it such the compiler will throw an error if some condition can block the button?)
2. Form2 or the request form cannot slow down or crash the main app. (henche the second thread and app)
2 It would be nice if form2 did what it was supposed to, or update the test in this case.

1. The compiler won't give you an error if something can block the form - because it can't know. However, you have to be careful not to do anything that can block it.
MessageBox, ShowDialog, etc. will all block a thread. So will any long operation. So all these need to be avoided in the thread that runs your main form.
2. You can run the second Form and its Application in a new thread - but you have to get the invocations right.
3. The command to bring a window to the Front is Activate() not BringToFront(). Change your line to Activate, and it works right.
 
Last edited:

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
First: I've edited my post because I was talking BS. Your code was almost right, but I didn't see the problem initially. Just that the idea of having multiple message-loops seemed a very strange way to solve the problem (but I can confirm that it does work). You need to fix your Invoke command (as I describe in the edited post).

The thing about a MessageBox is that it blocks the thread that it is running in. It is designed this way, so that the user can be informed of a problem that is stopping the program from continuing.

If you need an alert that doesn't block the thread - then you can just spawn a new form. Make a form that looks like a message box. Then just 'Show' it. It will run quite happily in the same thread as your main Form. This avoids any complicated cross-thread communication.

You could run a messagebox in another thread - but why add the complexity of another thread, when you can just use another form with an OK button and a Label in it.


1. The compiler won't give you an error if something can block the form - because it can't know. However, you have to be careful not to do anything that can block it.
MessageBox, ShowDialog, etc. will all block a thread. So will any long operation. So all these need to be avoided in the thread that runs your main form.
2. You can run the second Form and its Application in a new thread - but you have to get the invocations right.
3. The command to bring a window to the Front is Activate() not BringToFront(). Change your line to Activate, and it works right.

That worked great, calling the invoke on form2 did the trick. I added a this.Activate() it went to the front just like you said. This is using the ShowDialog, not Application.run. When is bringtofront supposed to work?
I will try the application way and see if it works.
The only issue left right now is if I kill the second form it kills the application. This is the only reason where a second application for form2 is beneficial.

I don't need any message boxes, I am just trying to come up with things that could block button1 and try to protect it.

Thanks for all you help. I will try expanding on the program to make it more like my final project which will hopefully make it easier to understand my requirements.
 
Last edited:

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
I tried the Application.Run method and it worked, but there was still only one process so killing it still killed both forms, but that is not as important at the moment. I will work on expanding the application and post it as soon as I can.

Thanks again.
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
WARNING: the new application currently can run the main thread and 4 worker threads, which cripples my dual-core machine while it is running so please be careful running all the workers at once.

Here is the link: http://rapidshare.com/files/416108723/ThreadTest2.zip

Let’s say that the application is a representation of a restaurant. I am the boss and I have 4 workers to do something. Working can be anything, taking orders, making sandwiches, waiting tables, ect. So I can see how much work each worker has done and I know how much total work has been completed.

Right now it is not perfect as the work counter restarts every time. I have not changed the worker process from your code yet. It would make more sense that each time I just give more work by increasing the work limit. (I know I am a bad boss)

Something that is not included yet is that all the workers should be aware of each other in the sense if one or several workers finish, they should help the other workers finish their work by taking some of the load. In code, lower the working limit and increase their limit and keep working. Also, there should be a break option, meaning that if a worker stops for a break, it should notify the other workers and they should work until it returns.
This is the easier case, the only problem is accurately checking the status of other workers.

There is another piece I have not included yet. There should be another data source that I technically cannot control which is my product provider.
This is a restaurant and to do work I need raw materials that I get from this external worker. For a sandwich I need 2 slices of bread, lettuce, pickles, tomato, ketchup and mustard, which is provided by other thread. The problem is that it is only one thread and it needs to supply products to all the threads.
Further more, I need to keep track of the produce I have available and when needed order more, and notify the workers if we are short some produce, to make less of the related products.
It really becomes an issue to not overload or overcall the supplying worker. All I technically need is one thread to be boss and handle the drawing, and one other thread between all the workers, assuming it makes it easier to work with the provider thread.

I know my explanation is not very clean and neither is my code. Hopefully it makes some sense though.

Please tell me what you think and if I can improve the current design.

I will try to enhance the application and try to better explain how it should run.

Thanks again.
 

Mark R

Diamond Member
Oct 9, 1999
8,513
14
81
There is another piece I have not included yet. There should be another data source that I technically cannot control which is my product provider.
This is a restaurant and to do work I need raw materials that I get from this external worker. For a sandwich I need 2 slices of bread, lettuce, pickles, tomato, ketchup and mustard, which is provided by other thread. The problem is that it is only one thread and it needs to supply products to all the threads.
Further more, I need to keep track of the produce I have available and when needed order more, and notify the workers if we are short some produce, to make less of the related products.
It really becomes an issue to not overload or overcall the supplying worker. All I technically need is one thread to be boss and handle the drawing, and one other thread between all the workers, assuming it makes it easier to work with the provider thread.

I'm not entirely clear what you mean. But it looks like you should consider using a ThreadPool to manage your workers.

The ThreadPool has a queue. You stick a job in the queue. The Threadpool gives it to the first available worker. If all the workers are busy, the job will wait in the queue until a worker gets to it. If the workers all stay busy then the ThreadPool will automatically create new workers to deal with the work. If there isn't enough work and the workers are idling too much, then it will start firing workers until it reaches an efficient state.

What it sounds like is that you want one master thread which essentially takes orders, and then feeds them to a ThreadPool which will then divide the orders up among the workers.
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
Sorry, I will try to clarify and add more to what should happen.

This being a restaurant, it is very important for how much I can get the supplies and how much I can sell the products.

So as the data source, lets say I have 1 PC with a display of every one of my supplies that I can buy for different prices and in different quantities. Lets say for one store I can buy bread 1 slice at a time, while another 2 slices and another 3 slices at a time. The more slices may be cheaper per slice, but I risk throwing away slices and loosing money.

Anyway, I at the start look at all the product sources and create tables for every combination to get to a needed sandwich. So lest say 1 sandwich takes 2 slices of bread, 1 slice of cheese, 1 leaf of lettuce, 3 slices of pickles, 2 squirts or ketchup and 3 squirts of mustard. So if I get 1 slice at a time I need to get 2 of these and buy everything else for the sandwich. If 2 at a time it is enough for a sandwich, and if it is 3 at a time, if I buy 2 3 at-a-times for 2 sandwiches. I also don't want to over-buy, as I might not sell all the sandwiches at the price I want.

So lets say I have one worker sitting at the computer monitoring all the supplier prices, and then I have a worker for each product source. Basically the one at the PC simply tells the handler that the price has changed. The guy gets updates from all the other condiment handlers of their prices and when it is updated sends it's new price to all the other condiments who need it as an event. As a result, all the supply handlers know how much all the other products cost without having to ask each one how much it costs. Also, only the product handler gets updates from the one guy who is at the computer.

So the lets say the 1 slice bread guy can get a slice for 50 cents each, but needs 2 for 1 dollar total, and it needs to buy a slice of cheese which it knows from the cheese guy costs 50 c each and a sheet of lettuce for another 50 cents for a total sandwich cost of 2 dollars. And it knows it can sell this sandwich for 2 dollars to break even.
So lets say I can all of a sudden I can get a slice for 40 cents each. If everything remains the same, I instantly make 20 cents per sandwich. I can even pay extra for the cheese or lettuce or even sell the sandwich for less and still make a profit.

Now, all buys have to go though the same PC as the data comes though, hence the single data thread. So if I need to buy more products I have to do it in a thread safe way. This can also cause a delay. Imagine a lunch rush were all prices go up so if I buy one product and miss the price on another I can loose money.

So in my code each one of the User control instances is it's own product source which gets data and notifies all it's partners of it's changes. So each individual piece knows what price it should try to buy to make a profit.

This can just as easily be adapted to buying a computer, you look for how much you can get a CPU, motherboard, ram, ect. and sometimes you can get bundles which may be cheaper, but possibly not as good.

I am not sure that a thread-pool is the right way to go since all the worker threads should always be running and waiting for new price updates and chances to buy. The code also depends on the price changes to usually occur much slower than the internal processing capability. So if one price updates, if should have time to notify the handler of the new price and it can notify his partners of the new price and he and all the partners can decide if they want to buy or not. However, it is very important that no 2 partners have different prices. I don't want one think it can buy bread at 40 cents a slice and another think it will buy for 50 cents per slice as this might result in inconsistent purchase actions.

Also, only the guy at the PC is aware of how to get prices or how to buy. The other threads only know that they can buy at some price, and only one piece of the thread is even aware of the guy at the PC to tell him to buy something.

Sorry, I know this is another very long explanation. This should be a much clearer example of what I want my program to do.

Thanks again.
 

elkinm

Platinum Member
Jun 9, 2001
2,146
0
71
Hi Again,

I still don't know how to make my full threaded program, but now I have a different need.

I need to create some kind of Audit Trail window that will show any important messages to the user. This is similar to logging, (which I also don't have yet) but only for select messages.

What I want is a new form with a DataGridview which will show status updates from the code.

If based on the threading application from before, I would like a time-stamp and a short description of what happened added in a new line.
An example would be buttto1 clicked, then button2 clicked, then worker1 started, worker2 started and so on.

Where threading comes in, I want the code to maintain all the changes in memory in a separate thread such that any part of the code can send a quick message to it and continue.
This second form does not need to be visible, but if it is launched it would show any events up to that point and keep updating when needed.

This seems very simple, just keep a table in memory and show form3 when needed with a binding to the table. The problem I am having is maintaining the new thread without the form running. I will see what I can get and post my solution.

Thanks