Semi-Random lock ups. Background worker and Access 2003 database involved.

Hello, I have a C# application that is almost complete, but I'm experiencing some hard to track down issues. The app is designed to sit in the system tray, waking up periodically to check various fields in an Access 2003 database, and send an email if needed. Double clicking the tray icon brings up a log in form and then a UI where the user can tweak settings and what not.

To achieve the scheduling, I start a BackgroundWorker when the app starts, and tell it to sleep for the SleepPeriod (user decides), using Thread.Sleep(). When it wakes up it uses a OleDbConnection to the db, checks the appropriate fields, sends emails if needed, and then goes to sleep again.

When the user hits the save button or minimizes the app (to the tray) all his settings are saved to tables in the same db using the same OleDbConnection.

It all works fine, except that for some reason the UI (main) thread hangs occasionally, seemingly at random. It seems to happen if you leave the app between one and four hours, but I've also had the same instance running for 3 days straight without it occurring.

It happens in the following manner: The user tries to restore the app by double clicking on the system tray, and the little log in form appears, but does not draw fully (bits of the background poke through) and is totally unresponsive. The background scheduling thread continues to work fine (send out emails, etc).

Oh, and I've also written a LogWriter that accepts Messages from both the scheduling and UI threads into a static Queue<Message>. When the LogWriter is created it starts another thread that wakes up every couple of minutes, and if the Message Queue is over a certain size, writes all the messages to a text file at once. This thread also continues to function as normal.

So, I don't know if you can help with the info I've been able to give you (might be too much). Any ideas on what could cause this sort of hang up (unresponsive windows, not even drawing) in a C# winforms app? Let me know if you'd like specific code snippets for anything I've described.

Also, on a potentially related note. Is it a good idea or a bad idea to use the same OleDbConnection across threads? I just now realized I'm doing this and might just have answered my own question. Except that the UI thread shouldn't be using the connection unless the user hits the "run now" button, which he obviously hasn't during the freeze ups, because they've typically happened overnight when the person is not around. Should I leave the connection open constantly, or open and close it whenever I need it?
KnowledgeWareAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

JimBrandleyCommented:
To eliminate any problems that might be caused by the connection, I would use a pool, opening only as needed, and closing as soon as that read (or transaction) is complete.

Jim
0
mastooCommented:
Ditto about thread pool since the documentation says:

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

"not guaranteed" means guaranteed to cause sporadic problems that are hard to trouble-shoot.
0
KnowledgeWareAuthor Commented:
Haha, thanks for the info you two. I have a suspicion that this is the solution, but I'll need time to implement and test. I'll probably give you guys some points tomorrow. :)
0
The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

JimBrandleyCommented:
Good luck. Come back at us if that's not the solution.

Jim
0
KnowledgeWareAuthor Commented:
Hey guys,

No dice. After two days of testing (and me thinking it was fixed) it seems to have happened again. :@

It's very random, and only seems to happen on my boss's computer. :S :P I've found out he's connecting multiple instances of this app (running on two different machines)  to the same database. Besides my app not really being designed for that (doesn't worry about concurrency issues at all), I don't think that could cause the lock-ups I'm seeing. I mean, even if the two machines both try and read the same record at the "same" time, the Access db should handle that just fine right? The system is idle before I lock up, neither one is writing to the db for a good couple of hours before the lockup. And on top of that, the background thread (started from a background worker) continues to run just fine and query the db periodically for the data to send out in emails (which we still recieve, even after the UI freeze). Still, I thought I should mention it.

Any other ideas? I've kind of got this idea running through my head that maybe another window is opening "behind" the login one (though I have no idea what), because I've noticed similar draw / response problems in similar situations. Think this could be it / how could I test for that?
0
JimBrandleyCommented:
Can you post the code that responds to the double-click and opens the login window?

Jim
0
KnowledgeWareAuthor Commented:
Here it is:
----frmMain----
 
private void notifyIcon_DoubleClick(object sender, EventArgs e)
        {
            if (!this.Visible)
            {
                if (Controller.LogInUser())
                {
                    if (SASettings.AutoStartUp) { SASettings.AutoStartUp = false; }
                    this.WindowState = FormWindowState.Maximized;
                    this.Show();
                }
            }
        }
 
 
-----Controller-----
 
static internal bool LogInUser()
        {
            LogWriter.Instance.WriteEvent("Starting Logon");
            using (frmLogin loginForm = new frmLogin())
            {
                DialogResult r = loginForm.ShowDialog();
                if (r == DialogResult.OK)
                {
                    LogWriter.Instance.WriteEvent("Logon Successful");
                    return true;
                }
                else if (r == DialogResult.Cancel)
                {
                    LogWriter.Instance.WriteEvent("Logon Cancelled");
                    return false;
                }
                else
                {
                    LogWriter.Instance.WriteEvent("Logon Failed");
                    DialogResult r2 = MessageBox.Show("Invalid email or password. Would you like to try again?", "Invalid Credentials", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                    if (r2 == DialogResult.Yes)
                    {
                        return Controller.LogInUser();
                    }
                }
            }
            return false;
        }

Open in new window

0
KnowledgeWareAuthor Commented:
As far as I can tell, it's not getting past line 24. Oh, here's the code that executes when the Login Form is shown:
public frmLogin()
        {
            InitializeComponent();
        }
 
private void frmLogin_Load(object sender, EventArgs e)
        {
            this.Activate();
            txtAdminEmail.Select();
            txtAdminEmail.Focus();
        }

Open in new window

0
JimBrandleyCommented:
Have you tried:
                DialogResult r = loginForm.Show();

instead of:
                DialogResult r = loginForm.ShowDialog();

I'm wondering if there might be some interaction between popping a modal dialog and this.Activate();

I know that's grasping at straws.

The only other thought I have is possibly suspending the background threads when this pops.

Jim
0
JimBrandleyCommented:
One more question: Have you looked at TaskManager when the freeze is in effect to see whether anything is tying up the CPU?

Jim
0
KnowledgeWareAuthor Commented:
I think I'd rather nuke this.Activate() than ShowDialog(), as Show() is non blocking and doesn't return a DialogResult. I'll give it a quick try.

That last is a good thought.

Do you know what happens if two separate threads call ShowDialog() on two different forms? I'm kind of grasping at straws too, but I'm guessing that the background thread could be throwing what I've called a "Warning" which is an exception that I don't want to crash the program, but the user may want to know about. It opens in a modal dialog, but from a different thread... I'll try flipping that to "Show()" and see if it helps.
0
KnowledgeWareAuthor Commented:
Yeah, we've looked at the memory / CPU usage, it all looks normal. Nothing else on the computer freezes / slows either, which would probably be the case if that was the cause.
0
mastooCommented:
You don't want anything other than the main gui thread popping up windows.  How about having your background thread store a member variable holding an error message and the main thread can poll that to look for errors that need to be announced?  Or have it use Invoke on the main thread so that the popup is managed by the main thread.  And does your boss have visual studio?  It might be helpful to attach the debugger to the app next time it gets stuck.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.