#c# #ios #multithreading #xamarin.ios #xamarin
#c# #iOS #многопоточность #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) amp;amp; 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);
}
Похоже, это работает очень хорошо, как поиск контактов в приложении mail. Однако, когда пользователь вводит быстро, приложение вылетает без каких-либо исключений. Кто-нибудь может предложить лучший способ планирования и синхронизации этих потоков поиска.
полный код
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. Сбой — это «ошибка malloc *** для объекта 0x double free». Я не смог найти, где это происходит, хотя
Ответ №1:
Это похоже на условие гонки в вашем коде. Я предполагаю, что происходит следующее:
- Вы запускаете несколько потоков filterThread, каждый из которых работает с одними и теми же данными без какой-либо синхронизации.
- При использовании
BeginInvokeOnMainThread
основной поток будет работать с одними и теми же данными, которые уже были изменены одновременно из нескольких потоков (и, вероятно, модифицируются, пока основной поток также использует данные), и вы в конечном итоге отправляете мусор в пользовательский интерфейс из основного потока, что в конечном итоге приводит к сбою.
Попробуйте убедиться, что вы одновременно запускаете только один filterThread, и никогда, пока основной поток обращается к тем же данным, которые использует filterThread.
Комментарии:
1. я внес изменения в код для блокировки критической области, как указано выше. Не видел сбоя.