WP7 - 在应用程序停用或关闭时无法正常退出 bg 线程
我的数据密集型 wp7 应用程序保存数据如下:我维护一个反映所有用户活动的更改日志,每隔几秒,线程计时器就会启动一个线程池线程,将更改日志刷新到事务内的数据库。它看起来像这样:
当用户退出时,我停止计时器,刷新 UI 线程上的日志(不超过一两秒),然后卸载数据库。
但是,如果用户退出时工作线程处于活动状态,我无法弄清楚如何优雅地做出反应。系统似乎杀死了工作线程,因此它永远不会完成其工作,也永远不会放弃其对数据库连接的锁,然后ui线程尝试获取锁,并立即被系统杀死。我尝试在 UI 线程上设置一个标志,请求工作线程中止,但我认为工作线程在读取该标志之前就被中断了。一切工作正常,除了百分之一的情况,其中一些用户更改最终没有保存到数据库,我似乎无法解决这个问题。
下面非常简化的代码:
private Timer _SweepTimer = new Timer(SweepCallback, null, 5000, 5000);
private volatile bool _BailOut = false;
private void SweepCallback(object state) {
lock (db) {
db.startTransaction();
foreach(var entry in changeJournal){
//CRUD entry as appropriate
if(_BailOut){
db.rollbackTransaction();
return;
}
}
db.endTransaction();
changeJournal.Clear();
}
}
private void RespondToSystemExit(){
_BailOut = true; //Set flag for worker to exit
lock(db){ //In theory, should acquire the lock after the bg thread bails out
SweepCallback(null);//Flush to db on the UI thread
db.dismount();//App is now ready to close
}
}
My somewhat data-intensive wp7 app persists data as follows: I maintain a change journal reflecting all user activity, and every couple of seconds, a thread timer spins up a threadpool thread that flushes the change journal to a database inside a transaction. It looks something like this:
When the user exits, I stop the timer, flush the journal on the UI thread (takes no more than a second or two), and dismount the DB.
However, if the worker thread is active when the user exits, I can't figure out how to react gracefully. The system seems to kill the worker thread, so it never finishes its work and never gives up its lock on the database connection, and the ui thread then attempts to acquire the lock, and is immediately killed by the system. I tried setting a flag on the UI thread requesting the worker to abort, but I think the worker was interrupted before it read the flag. Everything works fine except for this 1 in 100 scenario where some user changes end up not being saved to the db, and I can't seem to get around this.
Very simplified code below:
private Timer _SweepTimer = new Timer(SweepCallback, null, 5000, 5000);
private volatile bool _BailOut = false;
private void SweepCallback(object state) {
lock (db) {
db.startTransaction();
foreach(var entry in changeJournal){
//CRUD entry as appropriate
if(_BailOut){
db.rollbackTransaction();
return;
}
}
db.endTransaction();
changeJournal.Clear();
}
}
private void RespondToSystemExit(){
_BailOut = true; //Set flag for worker to exit
lock(db){ //In theory, should acquire the lock after the bg thread bails out
SweepCallback(null);//Flush to db on the UI thread
db.dismount();//App is now ready to close
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好吧,为了结束这个问题,我最终使用了手动重置事件而不是锁定,据我所知,这是对手动重置事件的误用,有风险和黑客行为,但总比没有好。
我仍然不知道为什么我的原始代码不起作用。
编辑:为了后代,我重新发布代码以从 MS 论坛重现此内容:
这里是几乎相同的代码,但在 WP7 上失败,只需制作一个带有两个按钮的页面并挂钩它们
Well, just to close this question, I ended up using a manualresetevent instead of the locking, which is to the best of my understanding a misuse of the manualresetevent, risky and hacky, but its better than nothing.
I still don't know why my original code wasn't working.
EDIT: For posterity, I'm reposting the code to reproduce this from the MS forums:
Here is nearly identical code that fails for WP7, just make a page with two buttons and hook them
当您通过
Application_Deactivated
或Application_Closing
事件进行操作时,您的方法应该有效。 MSDN 说:因此,如果您说只需要几秒钟,那应该没问题。除非文档没有讲述整个故事。或者你的工作线程退出所需的时间比你想象的要长。
Your approach should work when you operate from the
Application_Deactivated
orApplication_Closing
event. MSDN says:So if you say it just takes just a few seconds this should be fine. Unless the docs don't tell the whole story. Or your worker thread takes longer to exit than you think.
正如 Heinrich Ulbricht 已经说过的,你有 <=10 秒的时间来完成你的东西,但是你应该阻止 MainThread 来获取它们。
这意味着即使您的 BG 线程有很多工作要做,但您的 UI 线程在 OnClosingEvent/OnDeactivatingEvent 中什么也不做 - 您将不会获得 10 秒的时间。
我们的应用程序实际上在关闭事件中对 UI 线程进行永久等待,以允许 BG 线程通过套接字发送一些数据。
As Heinrich Ulbricht already said you have <=10 sec to finish your stuff, but you should block MainThread to get them.
It means that even if you have BG thread with much work to do, but your UI thread just does nothing in OnClosingEvent/OnDeactivatingEvent - you will not get your 10 seconds.
Our application actually does eternal wait on UI thread in closing event to allow BG thread send some data thru sockets.