المساعد الشخصي الرقمي

مشاهدة النسخة كاملة : What do you think of this? Multithreaded remote registry handler



C# Programming
06-12-2009, 02:32 AM
Here is my first attempt at writing a multi-threaded class.

The purpose of this class is to allow you to connect to a remote registry without things going bad if the remote machine doesn't respond. It also holds open remote connections for a predefined period before destroying the connection to allow for reuse.

I'd really like some feedback on the threading. Is it thread safe? Have I made any errors that might make it blow up in certain circumstances?

Many thanks!

using Microsoft.Win32;
using System;
using System.Threading;
using System.Collections.Generic;

namespace JacksTools
{
public class RemoteRegistryHandler
{
private class RegistryStub
{
private RegistryKey _reference;
private int _timeout;
private DateTime _lastAccessed;

public RegistryKey Reference
{
get {
_lastAccessed = System.DateTime.Now;
return _reference;
}
}

public Boolean TimedOut
{
get
{
return (_lastAccessed.AddMilliseconds(_timeout) < System.DateTime.Now);
}
}

public RegistryStub(int timeout, RegistryKey reference)
{
_lastAccessed = System.DateTime.Now;
_timeout = timeout;
_reference = reference;
}
}

Dictionary<String, RegistryStub> _store = new Dictionary<string,RegistryStub>();

private int _timeout;
private Thread _cleaner;
private Boolean _closingDown = false;

private class AttemptGet
{
private String _machineName;
private RegistryHive _hive;
public RegistryKey ResultKey;
public Exception Error;

public void Attempt()
{
try
{
ResultKey = RegistryKey.OpenRemoteBaseKey(_hive, _machineName);
}
catch (Exception e) {
Error = e;
Console.WriteLine("The following exception occured when attempting to connect a remote registry (" + _hive.ToString() + " on " + _machineName + ")\n" +
e.ToString());
}
}

public AttemptGet(String machineName, RegistryHive hive)
{
_machineName = machineName; _hive = hive;
}
}

public RegistryKey GetRemoteKey(String machineName, RegistryHive hive, int timeout)
{
lock (_store)
{
String key = machineName + hive.ToString();
if (_store.ContainsKey(key))
{
if (!_store[key].TimedOut)
{
return _store[key].Reference;
}
else
{
_store.Remove(key);
Console.WriteLine("RemoteRegistryHandler cleaned " + machineName + hive.ToString());
}
}
AttemptGet ag = new AttemptGet(machineName, hive);
Thread attemptThread = new Thread(new ThreadStart(ag.Attempt));
attemptThread.Name = "Attempting connection to registry " + hive.ToString() + " on " + machineName;
attemptThread.IsBackground = true;
attemptThread.Start();
attemptThread.Join(timeout);
RegistryKey reference = ag.ResultKey;
if (attemptThread.IsAlive) throw new TimeoutException();
if (reference == null) throw ag.Error;

RegistryStub newStub = new RegistryStub(_timeout, reference);
_store.Add(key, newStub);
Console.WriteLine("RemoteRegistryHandler added " + key);

if (_store.Count == 1)
{
_cleaner = new Thread(new ThreadStart(cleaner));
_cleaner.Start();
}

return newStub.Reference;
}
}

public void cleaner()
{
while (!_closingDown)
{
try
{
Thread.Sleep(_timeout);
lock (_store)
{
List<String> keys2Del = new List<String>();
foreach (KeyValuePair<String, RegistryStub> pair in _store)
{
if (pair.Value.TimedOut)
{
keys2Del.Add(pair.Key);
}
}
foreach (String key in keys2Del)
{
_store.Remove(key);
Console.WriteLine("RemoteRegistryHandler cleaned " + key);
}
}
if (_store.Count == 0) break;
}
catch (ThreadInterruptedException e)
{
if (_closingDown)
{
foreach (KeyValuePair<String, RegistryStub> pair in _store)
{
Console.WriteLine("RemoteRegistryHandler cleaned " + pair.Key);
}
_store.Clear();
}
}
}
}

public RemoteRegistryHandler(int timeout)
{
_timeout = timeout;
}

public void Close()
{
_closingDown = true;
if (_cleaner != null)
{
try
{
_cleaner.Interrupt();
_cleaner.Join();
}
catch (NullReferenceException e) { }
}
}
}
}