|
Hi,
I am creating one desktop application.in that application i want to add item without repetition.If i add duplicate item into datagridview this item can not be add but update their existing value.please help me.
|
|
|
|
|
Search the grid for that item already existing, and add or update as necessary.
|
|
|
|
|
I have a scenario where the application starts up and spawns a worker thread. When the main thread exits, I want the PROCESS (and the worker thread) to stay alive until its done doing its thing and then the whole process can exit. So I did something like this:
Thread threadCurrent = Thread.CurrentThread;
Task.Run(() =>
{
while (threadCurrent.IsAlive || (_queue.Count > 0))
Thread.Sleep(250);
});
This does exactly what I want. When the main application exits, the process keeps running until the queue is finished processing (_queue is processed in a separate thread, this code piece keeps the process alive) and then the process shuts down.
I'm not happy with the Sleep(250) portion because that part is going for the entire lifetime of the application. It's not spinning the CPU or anything. I'm just looking for a better way to do it.
I tried threadCurrent.Join(), however, that only works if the app is running in the debugger. I don't get why. If I have a debugger attached, the Join() blocks until the main thread is done as expected. If I don't have a debugger attached, the Join() never returns.
EDIT: I should also note that this code in a library, so I can't really require the developer to do anything special in the main thread to make this work.
|
|
|
|
|
|
As I specifically mentioned in my post, Thread.Join() only works on the main thread if the debugger is attached. I guess the debugger kills the main thread while without the debugger, the thread is not killed.
|
|
|
|
|
SledgeHammer01 wrote: only works on the main thread if the debugger is attached
That is definitely untrue. I use Join all the time.
|
|
|
|
|
Not what I'm seeing. If I do threadCurrent.Join() it works as expected IF THE DEBUGGER IS ATTACHED. When the main thread "is done" and my queue is empty, the whole process exits. If I ctrl-F5 it, it does keep the process alive, but it never gets past the threadCurrent.Join() and the process stays alive forever. Keep in mind that my worker thread is a FOREGROUND thread. That is required to keep the process alive.
|
|
|
|
|
OK, I second the remark that what you're saying isn't true.
You're going to have to back up what you're saying with the code because I think you're misinterpreting what the code is really doing.
|
|
|
|
|
If you say so ... but here you go... here's a simple console app that demonstrates it. Run this IN THE DEBUGGER (F5) and the process will exit after 5 seconds. Now run it again with CTRL-F5 (NO DEBUGGER ATTACHED) and you'll see the process never exits.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static bool b = false;
static void Main(string[] args)
{
Thread threadCurrent = Thread.CurrentThread;
Task.Run(() =>
{
threadCurrent.Join();
b = true;
});
Thread _threadWorker = new Thread(new ThreadStart(Worker));
_threadWorker.SetApartmentState(ApartmentState.STA);
_threadWorker.Start();
Thread.Sleep(5000);
}
private static void Worker()
{
while (true)
{
Thread.Sleep(100);
if (b)
break;
}
}
}
}
|
|
|
|
|
Very interesting. Well, I verified it. That's the most screwed up thing ever.
But, I hate to tell you this, but the one running under the debugger is lying to you. It's the one that's screwed up, not the one executing out of the debugger.
For some reason, the debugger is keeping the Task alive when it shouldn't be. Tasks are running out of the thread pool, which are all background threads. When your main thread exited, it took the Task with it, killing the threadCurrent.Join and never allowing it to get to b = true . That's why your worker thread stays alive.
I'd convert the Task to a foreground Thread instead.
[EDIT]
Oh, I almost forgot! You might want to post this on Connect[^] for a possible Visual Studio bug.
|
|
|
|
|
Tried the code this morning, first thing I did was change it to a foreground-thread. Strangely enough that made no difference at all.
I can imagine that the main-thread isn't terminated, but stopped by the debugger. That would explain why the background-task that should have terminated didn't.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Oh, I was going to try make that a foreground thread... so thanks for saving me the trouble .
Check out my response to Dave that further proves his explanation is not correctly. The main jist of the two further examples I posted was to prove that the Task is most certainly not getting killed and I wouldn't expect it to since the process is still alive.
|
|
|
|
|
Thank you for your attempt at an explanation of this bizarre behavior, but unfortunately, its not quite accurate . I will show you why with two further examples .
First off, we can all agree that Worker is a foreground thread and that it keeps the process alive regardless of what the main threads state is, right?
When the PROCESS exits, it will abort any BACKGROUND threads abruptly. We can all agree on that too.
Since Worker is blocking the process from exiting, there is no reason for any background threads to get killed since the process is still alive.
EXAMPLE #1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static bool b = false;
static void Main(string[] args)
{
Thread threadCurrent = Thread.CurrentThread;
Task.Run(() =>
{
while (threadCurrent.IsAlive)
{
System.Diagnostics.Debug.WriteLine("MAIN THREAD IS ALIVE");
Console.WriteLine("MAIN THREAD IS ALIVE");
Thread.Sleep(250);
}
System.Diagnostics.Debug.WriteLine("MAIN THREAD IS DEAD");
Console.WriteLine("MAIN THREAD IS DEAD");
b = true;
});
Thread _threadWorker = new Thread(new ThreadStart(Worker));
_threadWorker.SetApartmentState(ApartmentState.STA);
_threadWorker.Start();
Thread.Sleep(5000);
}
private static void Worker()
{
while (true)
{
Thread.Sleep(100);
if (b)
{
Console.WriteLine("2) MAIN THREAD IS DEAD");
break;
}
}
}
}
}
With this example, we can clearly see that the Task is not getting killed (or at least it appears that way) because everything works as expected. You get "MAIN THREAD IS ALIVE" messages for 5 seconds and then you get a "MAIN THREAD IS DEAD" message AND the "2) MAIN THREAD IS DEAD" message from the worker thread. Everything worked as expected and all messages were printed as expected and everything exited cleanly.
A race condition perhaps? Perhaps... Perhaps not . I've never gotten any of the messages not to print with this implementation, but lets bump up the 250ms sleep to 3000ms and try that...
Nope... still works as expected, everything behaves correctly .
EXAMPLE #2: This is my favorite one ... I'm just replacing the Task code from the code above with this Task implementation:
Task.Run(() =>
{
System.Diagnostics.Debug.WriteLine("WAITING FOR MAIN THREAD TO DIE");
Console.WriteLine("WAITING FOR MAIN THREAD TO DIE");
threadCurrent.Join(6000);
System.Diagnostics.Debug.WriteLine("MAIN THREAD IS DEAD");
Console.WriteLine("MAIN THREAD IS DEAD");
b = true;
});
Yes, a contrived example, but it clearly proves that the Task is not getting killed outside of the debugger since after the 6s timeout, the Task is still alive .
Any ideas? I will try using a foreground thread for the watch dog, but your original explanation doesn't explain what we're seeing with these two examples .
I certainly would NOT expect a task to get taken out by the main thread exiting. Background threads only get killed when there are no more foreground threads. There is one in this case: the Worker.
|
|
|
|
|
I think you have it backward. The main thread should wait on the background/worker thread, not the other way around.
|
|
|
|
|
It does seem like he's relying on a quirkish feature, doesn't it?
|
|
|
|
|
I think what I'm trying to do is pretty reasonable.
Worker is actually a service (think service in the sense of Dependency Injection or Service Locator pattern) that services a queue. I don't know when (or if) messages will get thrown into the queue, so the queue needs to be monitored for the life of the process (its a blocking queue). If Worker was a background task, I would either need the app to implement some kind of "wait for all the messages to be processed" behavior or have messages lost.
In fact, if I make the Worker a background thread and have the console app send a 1000 messages into the queue, the process would exit after only 1 or 2 of the messages were serviced. NOT DESIRABLE.
So while I stripped all that out of my examples, the real intention is for the watch dog task to wait for the main thread to shutdown AND all the remaining messages in the queue to be processed and then set "b = true" so the worker thread can shut down (which makes the process shutdown cleanly).
Not too unreasonable, huh?
Like I said in another response (I think to Eddy)... when I make reusable APIs, I like to encapsulate all the behavior / requirements / code I can into the class so the user of my API can use it in a simple way.
|
|
|
|
|
I didn't say that wasn't unreasonable.
What I said was relying on a quirk of background/forground threads.
What you're scribing, I would probably use either events or other callbacks to signal completions.
I wouldn't have the main thread terminating and then waiting for a "background" thread to terminate itself. I'd keep the main thread around waiting for the background to finish so the main thread can receive notification that it is done and can keep other things alive, such logging API's or other things.
|
|
|
|
|
It's actually a pretty similar scenario to a logging API, an asynchronous one. Think about Log4Net or NLog or whatever. They have an email listener for example. That's going to be "slow". But regardless, lets say your console app writes 1000 log entries to the log, the Log() method is going to return right away because its async. So the main thread is going to be done and exit after like a second, but its going to take the logger a minute or two or whatever to send all those emails. Yes, I could have a design like:
theLogger.Flush(); / theLogger.Shutdown();
and have that method block the main thread until its done.
or I can do what you said:
theLogger.OnComplete += blah...
and have the blah method block the main process. But I see a few issues with both of those methods IMHO
1) Just like my queue implementation, a logger queue isn't going to have log entries to write all the time... how is the logger to know when to send the OnComplete() notification? Lets say you send it every time the queue goes empty... ok, well, now you require even more work on the developers part as they have to know if this OnComplete() event is the one they really care about and then they have to couple that with some mechanism to block the thread. Then as the developer of the API, you're going to get blamed cuz the developer didn't implement it right!
2) the .Flush() / .Shutdown() / etc. is cleaner and much less error prone, but this requires the developer to remember to call .Flush() / .Complete() and of course, you'll get blamed for a "buggy framework" when they forget because "your framework should handle this automatically -- hanging is a 'bug'".
3) finally, and this kind of a nitpick on my part... I see a logger (and my queue) as a fire & forget thing... I don't care about getting logging notifications back, I don't care about whether the logging queue is empty or not, I don't want to concern myself with any of that. I simply want to call Log("whatever") and move on with my life. Same thing with my queue.
This is what I'm trying to implement here... a mechanism that'll shut down the queue automatically.
|
|
|
|
|
Do you also need to tell your watch dog to bark and attack the guy breaking into your house in the middle of the night? .
The whole point of the watch dog thread is to encapsulate expected behavior.
Expected behavior being that as a developer, if I send 100 items into the queue (an API), I would expect all 100 to get processed without me having to implement a "wait for the queue to be done" event of some sort. I want that to be encapsulated into the API magically.
What I'm getting at is, the Worker thread is automatically created when the application starts (as part of my API), I thought it'd be kind of cheezy to have to make the developer remember to call theAPI.Shutdown()...
That'd be like Microsoft making you add an Exit() call at the end of your main() in a console app.
|
|
|
|
|
Have a WatchDog object that implements IDisposable. Done.
|
|
|
|
|
Who creates the watch dog object? The developer? Or the API?
|
|
|
|
|
How would that work anyways? The user of the API would have to manually create the watch dog object in some class that lives in the main thread, correct? (if I'm understanding your idea). That's even uglier then calling theAPI.Shutdown().
|
|
|
|
|
Then shouldn't the API be IDisposable?
|
|
|
|
|
Mind you, I'm not trying to argue with you (just in case you are starting to get annoyed lol)...
The API is implemented as a service (in the DI / SL sense of the word service, not as a Windows Service), so the instance of my API ends up being a static singleton instance inside of the DI container. It wouldn't get disposed unless the user manually called Dispose on the container. Calling Dispose() on the container is only a requirement if the container contains objects with unmanaged resources that need to be freed up. That is *very* rare in my world as 99.99999% of our stuff is strictly managed.
I know I'm sounding picky by not wanting to add any additional burden on developers that I don't need to, but you'd have to understand the type of people I work with to understand why... . Like the type of people who milk a literal 5 minute task for 6 months to a year type of people. Like the type of people who rather then fix memory leaks in applications simply write scripts to reboot the machine daily type of people .
|
|
|
|
|
Isn't a thread an unmanaged resource?
|
|
|
|