Синхронизация данных Monotouch - почему мой код иногда вызывает ошибки sqlite? - PullRequest
3 голосов
/ 13 июля 2010

У меня есть следующие вызовы (на самом деле несколько больше, чем этот - это общий метод, который здесь обсуждается):

ThreadPool.QueueUserWorkItem(Database.Instance.RefreshEventData);
ThreadPool.QueueUserWorkItem(Database.Instance.RefreshLocationData);
ThreadPool.QueueUserWorkItem(Database.Instance.RefreshActData);

1-й вопрос - нормально ли вызывать методы, которые вызывают службы WCF, такие какэтот?Я попытался объединить их в цепочку, и это было беспорядок.

Пример одного из методов обновления, вызываемых выше, - это (все они следуют одному и тому же шаблону, просто вызывают разные службы и заполняют разные таблицы):

public void RefreshEventData (object state)
        {
            Console.WriteLine ("in RefreshEventData");
            var eservices = new AppServicesClient (new BasicHttpBinding (), new EndpointAddress (this.ServciceUrl));

            //default the delta to an old date so that if this is first run we get everything
            var eventsLastUpdated = DateTime.Now.AddDays (-100);

            try {
                eventsLastUpdated = (from s in GuideStar.Data.Database.Main.Table<GuideStar.Data.Event> ()
                    orderby s.DateUpdated descending
                    select s).ToList ().FirstOrDefault ().DateUpdated;

            } catch (Exception ex1) {
                Console.WriteLine (ex1.Message);
            }

            try {
                eservices.GetAuthorisedEventsWithExtendedDataAsync (this.User.Id, this.User.Password, eventsLastUpdated);
            } catch (Exception ex) {
                Console.WriteLine ("error updating events: " + ex.Message);
            }

            eservices.GetAuthorisedEventsWithExtendedDataCompleted += delegate(object sender, GetAuthorisedEventsWithExtendedDataCompletedEventArgs e) {

                try {

                    List<Event> newEvents = e.Result.ToList ();

                    GuideStar.Data.Database.Main.EventsAdded = e.Result.Count ();

                    lock (GuideStar.Data.Database.Main) {
                        GuideStar.Data.Database.Main.Execute ("BEGIN");

                        foreach (var s in newEvents) {

                            GuideStar.Data.Database.Main.InsertOrUpdateEvent (new GuideStar.Data.Event { 
                                Name = s.Name, 
                                DateAdded = s.DateAdded, 
                                DateUpdated = s.DateUpdated, 
                                Deleted = s.Deleted, 
                                StartDate = s.StartDate,
                                Id = s.Id, 
                                Lat = s.Lat, 
                                Long = s.Long   
                            });

                        }

                        GuideStar.Data.Database.Main.Execute ("COMMIT");
                        LocationsCount = 0;
                    }
                } catch (Exception ex) {
                    Console.WriteLine("error InsertOrUpdateEvent " + ex.Message);
                } finally {
                    OnDatabaseUpdateStepCompleted (EventArgs.Empty);
                }

            };
        }

OnDatabaseUpdateStepCompleted - просто выполняет итерацию счетчика updateComplete, когда он вызывается, и когда он знает, что все службы возвращаются нормально, он удаляет ожидающий счетчик и приложение продолжает.

Это работает ОК 1-йвремя 'раунд - но иногда это не так с одним из них: http://monobin.com/__m6c83107d

Я думаю, что первый вопрос - все ли это нормально?Я не привык использовать потоки и блокировки, поэтому я вхожу в новую почву для себя.Хорошо ли использовать QueueUserWorkItem?Должен ли я даже использовать блокировку перед выполнением массовой вставки / обновления?Вот пример:

public void InsertOrUpdateEvent(Event festival){

            try {
                if (!festival.Deleted) {
                    Main.Insert(festival, "OR REPLACE");
                }else{
                    Main.Delete<Event>(festival);
                }
            } catch (Exception ex) {
                Console.WriteLine("InsertOrUpdateEvent failed: " + ex.Message);
            }

        }

Тогда следующий вопрос - что я делаю не так, что вызывает проблемы с sqlite?

w: //

Ответы [ 2 ]

3 голосов
/ 22 июля 2010

Sqlite не является потокобезопасным.

Если вы хотите получить доступ к Sqlite из более чем одного потока, вы должны снять блокировку, прежде чем вы получите доступ к любым структурам, связанным с SQLite.

Пример:

lock (db){
      // Do your query or insert here
}
0 голосов
/ 14 июля 2010

Извините, конкретных ответов нет, но есть мысли:

Является ли SqlLite потокобезопасным? Я не уверен - может быть, это не так (обертке нет). Можете ли вы заблокировать более глобальный объект, чтобы два потока не вставлялись одновременно?

Вполне возможно, что MT GC становится немного чрезмерно восторженным и освобождает вашу струну до того, как она будет использована. Может быть, сохранить местную ссылку на него во время вставки? У меня такое случалось с контроллерами представления, где они были в массиве (особенно tabcontrollers), но если я не хранил переменную-член вместе со ссылкой, они получали GC.

Не могли бы вы получить данные в виде потока, затем поставить все в очередь и вставить их в один поток? По крайней мере, в качестве теста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...