2017-08-08 7 views
3

Xamarinプロジェクトでは、次のコードを持つPCLライブラリがあります。JsonConvert.DeserializeObjectとThreadAbortedException

ConcurrentQueue<SyncRequest>を定義します。

_syncConsumer = new Task(
       ProcessSyncQueue, 
       _syncConsumerCancellationTokenSource.Token); 
_syncConsumer.Start(); 

ProcessSyncQueue方法は、同期キューを走査しGetSyncableEntityメソッド呼び出し:オブジェクトの初期化に消費者Taskが装着された順番に

private async void ProcessSyncQueue() 
{ 
    while (true) 
    { 
     SyncRequest syncRequest; 
     if (_syncQueue.TryDequeue(out syncRequest)) 
     { 
      var syncableEntity = GetSyncableEntity(syncRequest); 
     } 
    } 
} 

GetSyncableEntityはJSONの逆シリアル化を行う:

private T GetSyncableEntity(SyncRequest syncRequest) 
{ 
    T syncableEntity = default(T); 

    try 
    { 
     syncableEntity = JsonConvert.DeserializeObject<T>(syncRequest.SynchronizationContent); 
    } 
    catch (Exception e) 
    { 

    } 

    return syncableEntity; 
} 

このステップでは、ThreadAbortedExceptionが表示されます。「スレッドが中止されましたエド 'メッセージ。 スタックトレース:

at Newtonsoft.Json.JsonTextReader.FinishReadStringIntoBuffer(Int32 charPos, Int32 initialPosition, Int32 lastWritePosition) 
    at Newtonsoft.Json.JsonTextReader.ReadStringIntoBuffer(Char quote) 
    at Newtonsoft.Json.JsonTextReader.ParseProperty() 
    at Newtonsoft.Json.JsonTextReader.ParseObject() 
    at Newtonsoft.Json.JsonTextReader.Read() 
    at Newtonsoft.Json.JsonReader.ReadAndAssert() 
    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) 
    at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) 
    at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings) 
    at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings) 
    at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value) 

は誰が起こっていると、それがどのように直列化復元されなければならないかを理解するために私たちを助けることができますか?

UPDATE: 私は消費者とawaitそれを初期化するためにTask.Runを使用して、レビューアが、私はCancellationTokenSourceを削除した提案として、もう少しコードを投稿してください。 そして、このようないくつかのテスト実装を作成しました:だから私たちはRequestSynchronizationForメソッドを呼び出して同期させることを企業に要求し

protected void RequestSynchronizationFor(
     string synchronizationKey, 
     T entity) 
    { 
     if (!_isInitialized) 
     { 
      InitializeSyncRequestsQueue(); 
     } 

     _syncQueue.Enqueue(GetSyncRequest(synchronizationKey, entity)); 
    } 

。コールドランであれば、dbからInitializeSyncRequestsQueueを呼び出し、Task.Runのコンシューマスレッドを待ってキューを初期化します。

private async void InitializeSyncRequestsQueue() 
    { 
     var syncRequests = GetSyncedRequests(); 

     foreach (var syncRequest in syncRequests) 
     { 
      _syncQueue.Enqueue(syncRequest); 
     } 

     await Task.Run(ProcessSyncQueue); 
    } 

消費者のタスクは、以前と同じことを行います。

private async Task ProcessSyncQueue() 
    { 
     while (true) 
     { 
      SyncRequest syncRequest; 
      if (_syncQueue.TryDequeue(out syncRequest)) 
      { 
       var syncableEntity = GetSyncableEntity(syncRequest); 
      } 
     } 
    } 

はまだ同じ例外が発生しました。それが分かりやすいかどうかは分かりませんが、単体テストからコードを実行しています。助言がありますか?

アップデート2:私は、私が最初に「更新」に投稿された変更をした後

、コールスタックは、同様に少し変更されました:

at Newtonsoft.Json.JsonSerializer.get_MetadataPropertyHandling() 
    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) 
    at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) 
    at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings) 
    at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings) 
    at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value) 

UPDATE 3: を私は偽物のすべてのコードを抽出デシリアライズしようとしたときに、サービスは、まだ、同じ例外があります:ユニットテストからトリガ

public class JsonDeserializeService<T> 
{ 
    private readonly bool _isInitialized; 

    private readonly ConcurrentQueue<SyncRequest> _syncQueue; 

    public JsonDeserializeService() 
    { 
     _isInitialized = false; 
     _syncQueue = new ConcurrentQueue<SyncRequest>(); 
    } 

    public void RequestSynchronizationFor(
     string synchronizationKey, 
     T entity) 
    { 
     if (!_isInitialized) 
     { 
      InitializeSyncRequestsQueue(); 
     } 

     _syncQueue.Enqueue(GetSyncRequest(synchronizationKey, entity)); 
    } 

    private async void InitializeSyncRequestsQueue() 
    { 
     var syncRequests = Enumerable.Empty<SyncRequest>(); 

     foreach (var syncRequest in syncRequests) 
     { 
      _syncQueue.Enqueue(syncRequest); 
     } 

     await Task.Run(ProcessSyncQueue); 
    } 

    private async Task ProcessSyncQueue() 
    { 
     while (true) 
     { 
      SyncRequest syncRequest; 
      if (_syncQueue.TryDequeue(out syncRequest)) 
      { 
       var syncableEntity = GetSyncableEntity(syncRequest); 
      } 
     } 
    } 

    private T GetSyncableEntity(SyncRequest syncRequest) 
    { 
     T syncableEntity = default(T); 

     try 
     { 
      syncableEntity = JsonConvert.DeserializeObject<T>(syncRequest.SynchronizationContent); 
     } 
     catch (Exception e) 
     { 
     } 

     return syncableEntity; 
    } 

    private SyncRequest GetSyncRequest(string synchronizationKey, T entity) 
    { 
     return new SyncRequest() 
     { 
      SynchronizationContent = JsonConvert.SerializeObject(entity), 
      SynchronizationDelayUntil = DateTime.Now 
     }; 
    } 
} 

public void Syncable_Service_Should_Not_Generate_Exception() 
    { 
     var syncService = new JsonDeserializeService<FakeSyncableEntity>(); 
     syncService.RequestSynchronizationFor("syncKey", new FakeSyncableEntity() { Content = "Content" }); 
    } 
+1

もっとコードをリンクして問題を切り分けてください。あなたが示していることから、スレッドを中止する可能性があることを伝えるのは難しいです。 _syncConsumerCancellationTokenSourceに続いています。トークンは私が考える犯人になるでしょう – Dbl

+0

これはConcurrentQueueの外部で動作しますか? –

+1

「新しいタスク」を使用しないでください。代わりにTask.Run(ProcessSyncQueue、_syncConsumerCancellationTokenSource.Token)を使用してください。 _syncConsumerオブジェクトはどうなりますか?あなたはそれを待っていますか?エラーメッセージは、実行中のタスクオブジェクトと関連するスレッドが中止されたときに、そのタスクオブジェクトが処理されることを示唆することがあります。 – ckuri

答えて

0

この動作の理由は非常に簡単です。 あなたのテストは非同期タスクよりも終わりです。テストが終了すると、子スレッドのThreadAbortExceptionが発生します。

メインスレッドがタスクの完了を待つようにするには、task.Wait()を呼び出す必要があります。

関連する問題