C
C#2mo ago
Dingus

WPF possible threading issue?

I am creating a application to update a bunch of usb devices at the same time. I have figured out the usb communication with devices just fine but somehow someway I get a threading issue. I am just getting into threading so I just need someone with personal experience on how they would handle this situation. I have a System.Management object to watch for usb events. When usb connect/disconnect event fires off then check all devices connected by specific usb protocol and look at device paths for PID/VID (specific to manufacturer).
public MainWindow()
{
InitializeComponent();
StartDeviceDetection();
}

public void StartDeviceDetection()//start device detection through USB
{
ManagementEventWatcher watcher = new ManagementEventWatcher();
WqlEventQuery query = new WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_USBControllerDevice'"); //Querey for specific device standard
watcher.EventArrived += USBEvents; //subscribe to events it should querey for
watcher.Query = query; //Set Query
watcher.Start();//start watch
}

private void USBEvents(object sender, EventArrivedEventArgs e)//detects when device is removed from computer
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
eventType = e.NewEvent.ClassPath.ClassName;
//scanning for device arrival
if (eventType.Equals("__InstanceCreationEvent"))
{
aDeviceArrived();
}
}

private void aDeviceArrive(){
List<string> allPaths = {list of all paths with specific}
foreach(string path in allPaths){
if(path.Contains(VID) && path.Contains(PID)){
Device device = new Device();
device.path = path;
gridWithDevices.add(device);
}
}
public MainWindow()
{
InitializeComponent();
StartDeviceDetection();
}

public void StartDeviceDetection()//start device detection through USB
{
ManagementEventWatcher watcher = new ManagementEventWatcher();
WqlEventQuery query = new WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_USBControllerDevice'"); //Querey for specific device standard
watcher.EventArrived += USBEvents; //subscribe to events it should querey for
watcher.Query = query; //Set Query
watcher.Start();//start watch
}

private void USBEvents(object sender, EventArrivedEventArgs e)//detects when device is removed from computer
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
eventType = e.NewEvent.ClassPath.ClassName;
//scanning for device arrival
if (eventType.Equals("__InstanceCreationEvent"))
{
aDeviceArrived();
}
}

private void aDeviceArrive(){
List<string> allPaths = {list of all paths with specific}
foreach(string path in allPaths){
if(path.Contains(VID) && path.Contains(PID)){
Device device = new Device();
device.path = path;
gridWithDevices.add(device);
}
}
4 Replies
Dingus
Dingus2mo ago
The issue starts when I press button in datagrid that is beside objects listed usb path
Public BackgroundWorker worker
private void updateDevice(object sender, RoutedEventArgs e){
Device device = (sender as Button).DataContext as Device;
worker = new BackgroundWorker();
worker.DoWork += updateDeviceWithFiles;
worker.RunWrokerAsync(argument: device);
worker.dispose();
}
Public BackgroundWorker worker
private void updateDevice(object sender, RoutedEventArgs e){
Device device = (sender as Button).DataContext as Device;
worker = new BackgroundWorker();
worker.DoWork += updateDeviceWithFiles;
worker.RunWrokerAsync(argument: device);
worker.dispose();
}
Right now the device communication works wonderfully and all files are sent to the device. The application doesn't freeze up since I am using the new thread to actually send the files. HOWEVER I update a ton of devices. (4 at once usually). When all files are sent a the device I have device removed from datagrid so I assume it does not exist anymore and Garbage collecter reclaims the memory. It always happens at the 6th device when I press its update button debugger in visual studio says System.OutofMemoryException and points to threading method of claiming thread. What I think is happening is that after worker finishes sending files to device the thread is not actually disposed and Visual Studio thinks I am just infinitely trying to claim threads so visual studio yells at me. If I am not implementing threading right please tell me a more proper way to do it! This program has been months in the making by myself trying to figure out USB protocol and file handling. I just want to be able to update all my devices at once!
sibber
sibber2mo ago
i dont think you want to dispose the worker immediately after starting the work also io is inherently async you probably dont need a seperate thread for that and nowadays we use the TPL can you show updateDeviceWithFiles?
cap5lut
cap5lut2mo ago
can u also give the exact exception, including the stack trace? reason is OOMEs are not only thrown for the lack of memory (eg System.Drawing stuff throws them for invalid/unsupported image formats)
Dingus
Dingus2mo ago
The updateDeviceWithFiles gets into the weeds of the program. I actually discovered I was missing an important method of the class I am using with all the dll imports from setupapi.dll in windows. updateDeviceWithFiles goes essentially like this though. I am testing right now with the new function and seeing how it works then will report back here if I still have the same issue
async void updateDeviceWithFiles(motorollaDevice device)
{
// Check handle on specific device
Intpntr deviceHandle = DeviceManager.CreateFile(device.devicePath);

bool success = deviceHandle != IntPtr.Zero && deviceHandle != new IntPtr(-1);
IntPtr fileHandle = 0;

if (success)
{
List<string> filesForSelectedDevice = deviceFiles(); //here I grab files from database

while (x < fileCount)
{
currentFileCount(device, x, fileCount);
Thread.SpinWait(500);
deviceHandle = DeviceManager.CreateFile(device.devicePath);
//make sure device exists

success = deviceHandle != IntPtr.Zero && deviceHandle != new IntPtr(-1);
if (success)
{
fileHandle = DeviceManager.CreateFile(filesForSelectedDevice[x]);
//make sure file exists

ProcessSelectedFileAsync(deviceHandle, fileHandle, device);


DeviceManager.CloseHandle(fileHandle);
x++;
}
if (x == fileCount)
{
DeviceManager.CloseHandle(deviceHandle); //dispose handle on device
DeviceManager.SetupDiDestroyDeviceInfoList(deviceHandle);
//this is the function I was missing to release memory related to device causing my thread to be held

removeFinishedDevice(device);
break;
}
}
async void updateDeviceWithFiles(motorollaDevice device)
{
// Check handle on specific device
Intpntr deviceHandle = DeviceManager.CreateFile(device.devicePath);

bool success = deviceHandle != IntPtr.Zero && deviceHandle != new IntPtr(-1);
IntPtr fileHandle = 0;

if (success)
{
List<string> filesForSelectedDevice = deviceFiles(); //here I grab files from database

while (x < fileCount)
{
currentFileCount(device, x, fileCount);
Thread.SpinWait(500);
deviceHandle = DeviceManager.CreateFile(device.devicePath);
//make sure device exists

success = deviceHandle != IntPtr.Zero && deviceHandle != new IntPtr(-1);
if (success)
{
fileHandle = DeviceManager.CreateFile(filesForSelectedDevice[x]);
//make sure file exists

ProcessSelectedFileAsync(deviceHandle, fileHandle, device);


DeviceManager.CloseHandle(fileHandle);
x++;
}
if (x == fileCount)
{
DeviceManager.CloseHandle(deviceHandle); //dispose handle on device
DeviceManager.SetupDiDestroyDeviceInfoList(deviceHandle);
//this is the function I was missing to release memory related to device causing my thread to be held

removeFinishedDevice(device);
break;
}
}