Added locking on a collection to clear up potential thread safety issues

Haven't encountered it myself but it does look like it could
have been possible
This commit is contained in:
Travis Nickles 2019-12-28 13:14:21 -06:00
parent 74ea3e674f
commit 91c09c025a

View File

@ -1,7 +1,9 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Media; using System.Windows.Media;
@ -11,7 +13,8 @@ namespace DS4WinWPF.DS4Forms.ViewModels
{ {
public class ControllerListViewModel public class ControllerListViewModel
{ {
private object _colLockobj = new object(); //private object _colLockobj = new object();
private ReaderWriterLockSlim _colListLocker = new ReaderWriterLockSlim();
private ObservableCollection<CompositeDeviceModel> controllerCol = private ObservableCollection<CompositeDeviceModel> controllerCol =
new ObservableCollection<CompositeDeviceModel>(); new ObservableCollection<CompositeDeviceModel>();
private Dictionary<int, CompositeDeviceModel> controllerDict = private Dictionary<int, CompositeDeviceModel> controllerDict =
@ -56,27 +59,60 @@ namespace DS4WinWPF.DS4Forms.ViewModels
idx++; idx++;
} }
BindingOperations.EnableCollectionSynchronization(controllerCol, _colLockobj); //BindingOperations.EnableCollectionSynchronization(controllerCol, _colLockobj);
BindingOperations.EnableCollectionSynchronization(controllerCol, _colListLocker,
ColLockCallback);
}
private void ColLockCallback(IEnumerable collection, object context,
Action accessMethod, bool writeAccess)
{
if (writeAccess)
{
_colListLocker.EnterWriteLock();
}
else
{
_colListLocker.EnterReadLock();
}
accessMethod?.Invoke();
if (writeAccess)
{
_colListLocker.ExitWriteLock();
}
else
{
_colListLocker.ExitReadLock();
}
} }
private void Service_HotplugController(ControlService sender, DS4Device device, int index) private void Service_HotplugController(ControlService sender, DS4Device device, int index)
{ {
CompositeDeviceModel temp = new CompositeDeviceModel(device, CompositeDeviceModel temp = new CompositeDeviceModel(device,
index, Global.ProfilePath[index], profileListHolder); index, Global.ProfilePath[index], profileListHolder);
_colListLocker.EnterWriteLock();
controllerCol.Add(temp); controllerCol.Add(temp);
controllerDict.Add(index, temp); controllerDict.Add(index, temp);
_colListLocker.ExitWriteLock();
device.Removal += Controller_Removal; device.Removal += Controller_Removal;
} }
private void ClearControllerList(object sender, EventArgs e) private void ClearControllerList(object sender, EventArgs e)
{ {
_colListLocker.EnterReadLock();
foreach (CompositeDeviceModel temp in controllerCol) foreach (CompositeDeviceModel temp in controllerCol)
{ {
temp.Device.Removal -= Controller_Removal; temp.Device.Removal -= Controller_Removal;
} }
_colListLocker.ExitReadLock();
_colListLocker.EnterWriteLock();
controllerCol.Clear(); controllerCol.Clear();
controllerDict.Clear(); controllerDict.Clear();
_colListLocker.ExitWriteLock();
} }
private void ControllersChanged(object sender, EventArgs e) private void ControllersChanged(object sender, EventArgs e)
@ -85,7 +121,8 @@ namespace DS4WinWPF.DS4Forms.ViewModels
foreach (DS4Device currentDev in controlService.slotManager.ControllerColl) foreach (DS4Device currentDev in controlService.slotManager.ControllerColl)
{ {
bool found = false; bool found = false;
foreach(CompositeDeviceModel temp in controllerCol) _colListLocker.EnterReadLock();
foreach (CompositeDeviceModel temp in controllerCol)
{ {
if (temp.Device == currentDev) if (temp.Device == currentDev)
{ {
@ -93,16 +130,20 @@ namespace DS4WinWPF.DS4Forms.ViewModels
break; break;
} }
} }
_colListLocker.ExitReadLock();
if (!found) if (!found)
{ {
//int idx = controllerCol.Count; //int idx = controllerCol.Count;
_colListLocker.EnterWriteLock();
int idx = controlService.slotManager.ReverseControllerDict[currentDev]; int idx = controlService.slotManager.ReverseControllerDict[currentDev];
CompositeDeviceModel temp = new CompositeDeviceModel(currentDev, CompositeDeviceModel temp = new CompositeDeviceModel(currentDev,
idx, Global.ProfilePath[idx], profileListHolder); idx, Global.ProfilePath[idx], profileListHolder);
controllerCol.Add(temp); controllerCol.Add(temp);
controllerDict.Add(idx, temp); controllerDict.Add(idx, temp);
_colListLocker.ExitWriteLock();
currentDev.Removal += Controller_Removal; currentDev.Removal += Controller_Removal;
} }
} }
@ -111,6 +152,7 @@ namespace DS4WinWPF.DS4Forms.ViewModels
private void Controller_Removal(object sender, EventArgs e) private void Controller_Removal(object sender, EventArgs e)
{ {
DS4Device currentDev = sender as DS4Device; DS4Device currentDev = sender as DS4Device;
_colListLocker.EnterReadLock();
foreach (CompositeDeviceModel temp in controllerCol) foreach (CompositeDeviceModel temp in controllerCol)
{ {
if (temp.Device == currentDev) if (temp.Device == currentDev)
@ -120,6 +162,7 @@ namespace DS4WinWPF.DS4Forms.ViewModels
break; break;
} }
} }
_colListLocker.ExitReadLock();
} }
} }