diff --git a/src/MonoTorrent/MonoTorrent.Client/ClientEngine.cs b/src/MonoTorrent/MonoTorrent.Client/ClientEngine.cs index aebc5511c..3edce9b99 100644 --- a/src/MonoTorrent/MonoTorrent.Client/ClientEngine.cs +++ b/src/MonoTorrent/MonoTorrent.Client/ClientEngine.cs @@ -174,6 +174,8 @@ public async Task SaveStateAsync (string pathToStateFile) #region Member Variables + readonly SemaphoreSlim dhtNodeLocker; + readonly ListenManager listenManager; // Listens for incoming connections and passes them off to the correct TorrentManager int tickCount; /// @@ -269,6 +271,7 @@ public ClientEngine (EngineSettings settings) CheckSettingsAreValid (Settings); allTorrents = new List (); + dhtNodeLocker = new SemaphoreSlim (1, 1); publicTorrents = new List (); Torrents = new ReadOnlyCollection (publicTorrents); @@ -823,12 +826,19 @@ async ReusableTasks.ReusableTask MaybeSaveDhtNodes () if (nodes.Length == 0) return; - await Task.Run (() => { + // Perform this action on a threadpool thread. + await MainLoop.SwitchThread (); + + // Ensure only 1 thread at a time tries to save DhtNodes. + // Users can call StartAsync/StopAsync many times on + // TorrentManagers and the file write could happen + // concurrently. + using (await dhtNodeLocker.EnterAsync ().ConfigureAwait (false)) { var savePath = Settings.GetDhtNodeCacheFilePath (); var parentDir = Path.GetDirectoryName (savePath); Directory.CreateDirectory (parentDir); File.WriteAllBytes (savePath, nodes); - }); + } } public async Task UpdateSettingsAsync (EngineSettings settings)