键入时用于搜索的多个线程导致崩溃

时间:2014-07-02 17:21:36

标签: c# ios multithreading xamarin.ios xamarin

我正在使用xamarin / monotouch作为ios应用程序。在其中一个搜索屏幕中,当用户键入字符时,我会显示弹出的地址簿中的结果。我有大约5000个联系人,因此我在一个单独的线程中进行过滤,如下所示。

Thread filterThread = new Thread( new ThreadStart( delegate {

                   // Some ui code


                    PersonSearchModal.find (findstr);
                    var personList = PersonSearchModal.getResult ();


                    // followed by some ui code to update pop up with person list


            }));
            filterThread.Start ();

以下是搜索5000个联系人的方法

public static void find(string str)
        {
            lock (filterLock) {
                bool next = false;
                if (str.Length == 1)
                    clear ();

                if (results.Count == 0) {
                    next = true;
                } else {
                    PersonSearchResult r = results [results.Count - 1];
                    if (str.StartsWith (r.findstr, StringComparison.OrdinalIgnoreCase)) {
                        next = true;
                    }
                }
                if (next) {
                    findNext (str);
                } else {
                    findPrev ();
                }
            }
        }

public static void findNext(string str)
        {
            if (str.Trim ().Length == 0)
                return;

            Func<string, bool> filter = s => !String.IsNullOrWhiteSpace(s) && s.StartsWith(str, StringComparison.OrdinalIgnoreCase);
            var peoplefrom = results.Count > 0 ? getResult() : people;
            var personList = peoplefrom.
                Where(p => filter(p.FirstName) 
                    || filter(p.LastName) 
                    || p.GetEmails().Select(e => e.Value).Any(filter)).ToList();

            var result = new PersonSearchResult ();
            result.findstr = str;
            result.people = personList;
            results.Add (result);
        }

它似乎非常像邮件应用中的联系人搜索。但是,当用户快速输入时,应用程序会崩溃,没有任何异常。任何人都可以建议一种更好的方法来安排和同步这些搜索线程。

完整代码

public void filterContact(RectangleF rect, string searchstring)
        {

            ThreadPool.QueueUserWorkItem ( o => filter (rect, searchstring));

        }

        void filter(RectangleF rect, string searchstring)
        {

            lock (this) {
                try {
                    if (searchstring.Trim () == "") {
                        using (var pool = new NSAutoreleasePool ()) {
                            pool.InvokeOnMainThread (delegate {
                                if (DetailViewPopover != null) {
                                    DetailViewPopover.Dismiss (false);
                                }
                                return;
                            });
                        }
                        return;
                    }
                    string findstr = searchstring;
                    if (PersonSearchModal.people.Count == 0)
                        return;


                    PersonSearchModal.find (findstr);
                    var personList = PersonSearchModal.getResult ();


                    using (var pool = new NSAutoreleasePool ()) {
                        pool.InvokeOnMainThread (delegate {

                            if (personList.Count == 0) {
                                if (DetailViewPopover != null)
                                    DetailViewPopover.Dismiss (false);
                                return;
                            }

                            if (DetailViewPopover != null) {
                                _emailPickerController._searchName = searchstring;
                                PersonEmailPickerViewControllerSource PEsource = (PersonEmailPickerViewControllerSource)_emailPickerController.TableView.Source;
                                PEsource.personList = personList;
                                _emailPickerController.TableView.ReloadData ();

                                if (!DetailViewPopover.PopoverVisible) {
                                    DetailViewPopover.PopoverContentSize = new SizeF (400, 300);
                                    DetailViewPopover.PresentFromRect (rect, this.View, UIPopoverArrowDirection.Up, true);
                                } 

                            } else {
                                _emailPickerController = PersonEmailPickerViewController.GetInstance ();
                                _emailPickerController._searchName = searchstring;
                                PersonEmailPickerViewControllerSource PEsource = (PersonEmailPickerViewControllerSource)_emailPickerController.TableView.Source;
                                PEsource.personList = personList;
                                _emailPickerController.TableView.ReloadData ();
                                DetailViewPopover = new UIPopoverController (_emailPickerController);
                                DetailViewPopover.PopoverContentSize = new SizeF (400, 300);
                                DetailViewPopover.PresentFromRect (rect, this.View, UIPopoverArrowDirection.Up, true);
                            }
                        });
                    }

                } catch (System.Exception) {

                }
            }

        }

1 个答案:

答案 0 :(得分:0)

这看起来像是代码中的竞争条件。我的猜测是发生了以下情况:

  • 启动多个filterThread线程,每个线程处理相同的数据而不进行任何同步。
  • 使用BeginInvokeOnMainThread时,主线程将处理相同的数据,这些数据已经从几个线程同时修改(并且可能在主线程也使用数据时被修改),以及你最终从主线程向UI提供垃圾,最终导致崩溃。

尝试确保您只是同时运行一个filterThread,并且从不在主线程访问filterThread正在使用的相同数据时。