multithreading - WP7-在停用或关闭应用程序时无法正常退出bg线程时遇到麻烦

标签 multithreading windows-phone-7 windows-phone-7.1

我的数据密集型wp7应用程序按以下方式持久存储数据:我维护一个反射(reflect)所有用户 Activity 的变更日志,每隔几秒钟,线程计时器就会启动一个线程池线程,该线程将变更日志刷新到事务内的数据库中。看起来像这样:

当用户退出时,我停止计时器,刷新UI线程上的日志(不超过一两秒钟),然后卸下数据库。

但是,如果在用户退出时工作线程处于 Activity 状态,则无法弄清楚如何正常响应。系统似乎杀死了工作线程,因此它永远不会完成工作,也永远不会放弃对数据库连接的锁定,然后ui线程会尝试获取该锁定,并立即被系统杀死。我尝试在UI线程上设置一个标志以请求工作程序中止,但是我认为工作程序在读取该标志之前已被中断。一切正常,除了这种情况,即每100个场景中有1个场景,其中某些用户更改最终没有保存到数据库,而我似乎无法解决这一问题。

下面的代码非常简化:

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
    }
}

最佳答案

好了,只是为了解决这个问题,我最终使用了一个manualresetevent而不是锁定,据我所知,这是对manualresetevent的误用,既冒险又骇人,但总比没有好。

我仍然不知道为什么我的原始代码无法正常工作。

编辑:为了后代,我在重新发布代码以从MS论坛中重现此代码:

//This is a functioning console app showing the code working as it should. Press "w" and then "i" to start and then interrupt the worker
using System;
using System.Threading;

namespace deadlocktest {
    class Program {
        static void Main(string[] args) {
            var tester = new ThreadTest();
            string input = "";
            while (!input.Equals("x")) {
                input = Console.ReadLine();

                switch (input) {
                    case "w":
                        tester.StartWorker();
                        break;
                    case "i":
                        tester.Interrupt();
                        break;
                    default:
                        return;
                }
            }
        }
    }

    class ThreadTest{
        private Object lockObj = new Object();
        private volatile bool WorkerCancel = false;

        public void StartWorker(){
            ThreadPool.QueueUserWorkItem((obj) => {
                if (Monitor.TryEnter(lockObj)) {
                    try {
                        Log("Worker acquired the lock");
                        for (int x = 0; x < 10; x++) {
                            Thread.Sleep(1200);
                            Log("Worker: tick" + x.ToString());
                            if (WorkerCancel) {
                                Log("Worker received exit signal, exiting");
                                WorkerCancel = false;
                                break;
                            }
                        }
                    } finally {
                        Monitor.Exit(lockObj);
                        Log("Worker released the lock");
                    }
                } else {
                    Log("Worker failed to acquire lock");
                }
            });
        }

        public void Interrupt() {
            Log("UI thread - Setting interrupt flag");
            WorkerCancel = true;

            if (Monitor.TryEnter(lockObj, 5000)) {
                try {
                    Log("UI thread - successfully acquired lock from worker");
                } finally {
                    Monitor.Exit(lockObj);
                    Log("UI thread - Released the lock");
                }
            } else {
                Log("UI thread - failed to acquire the lock from the worker");
            }
        }

        private void Log(string Data) {
            Console.WriteLine(string.Format("{0} - {1}", DateTime.Now.ToString("mm:ss:ffff"), Data));
        }
    }
}

这是几乎相同的代码,它们对于WP7都失败了,只需要创建一个带有两个按钮的页面并将其钩住即可
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows;
using Microsoft.Phone.Controls;

namespace WorkerThreadDemo {
    public partial class MainPage : PhoneApplicationPage {
        public MainPage() {
            InitializeComponent();
        }

        private Object lockObj = new Object();
        private volatile bool WorkerCancel = false;
        private void buttonStartWorker_Click(object sender, RoutedEventArgs e) {
            ThreadPool.QueueUserWorkItem((obj) => {
                if (Monitor.TryEnter(lockObj)) {
                    try {
                        Log("Worker acquired the lock");
                        for (int x = 0; x < 10; x++) {
                            Thread.Sleep(1200);
                            Log("Worker: tick" + x.ToString());
                            if (WorkerCancel) {
                                Log("Worker received exit signal, exiting");
                                WorkerCancel = false;
                                break;
                            }
                        }
                    } finally {
                        Monitor.Exit(lockObj);
                        Log("Worker released the lock");
                    }
                } else {
                    Log("Worker failed to acquire lock");
                }
            });
        }

        private void Log(string Data) {
            Debug.WriteLine(string.Format("{0} - {1}", DateTime.Now.ToString("mm:ss:ffff"), Data));
        }

        private void buttonInterrupt_Click(object sender, RoutedEventArgs e) {
            Log("UI thread - Setting interrupt flag");
            WorkerCancel = true;

            //Thread.Sleep(3000); UNCOMMENT ME AND THIS WILL START TO WORK! 
            if (Monitor.TryEnter(lockObj, 5000)) {
                try {
                    Log("UI thread - successfully acquired lock from worker");
                } finally {
                    Monitor.Exit(lockObj);
                    Log("UI thread - Released the lock");
                }
            } else {
                Log("UI thread - failed to acquire the lock from the worker");
            }
        }
    }
}

关于multithreading - WP7-在停用或关闭应用程序时无法正常退出bg线程时遇到麻烦,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7838293/

相关文章:

c++ - 如何传递 opencv 图像以在不同线程的 Qt 场景中显示?

windows-phone-7 - 在页面 NavigationService.GoBack() 上传递数据

c# - MVVM WPF 中的列表框滚动事件

silverlight - 向 WP7 应用程序添加外部字体

ios - 很多关于 GCD 和串行队列的困惑

java - 根据 AsyncTask.execute() 在同一代码块中的运行方式显示 AlertDialog

c# - Json解析C#

c# - 将 windows phone 7 proj 转换为 win mobile 6.5?

windows-phone-7.1 - 捏缩放列表框中绑定(bind)的图像

c# multithreading发送3个不同的线程