C# 监视队列的线程<;行动>;
我正在做一个使用SNMP映射网络(仅限路由器)的小项目。为了加快速度,除了第一个由主线程完成的任务外,我还尝试拥有一个线程池来负责完成我需要的任务 此时我有两个工作,一个接受参数,另一个不接受:C# 监视队列的线程<;行动>;,c#,multithreading,snmp,C#,Multithreading,Snmp,我正在做一个使用SNMP映射网络(仅限路由器)的小项目。为了加快速度,除了第一个由主线程完成的任务外,我还尝试拥有一个线程池来负责完成我需要的任务 此时我有两个工作,一个接受参数,另一个不接受: UpdateDeviceInfo(网络设备nd) UpdateLinks()*尚未定义 我试图实现的是让那些工作线程等待作业完成 出现在队列上并在队列为空时等待。主线程将添加第一个作业,然后等待可能添加更多作业的所有工作线程完成,然后再开始添加第二个作业并唤醒休眠线程 我的问题是: 如何定义队列,
UpdateDeviceInfo(网络设备nd)
*尚未定义UpdateLinks()
队列上
并在队列为空时等待。主线程将添加第一个作业,然后等待可能添加更多作业的所有工作线程完成,然后再开始添加第二个作业并唤醒休眠线程
我的问题是:
- 如何定义
,以便插入方法和参数(如果有)。如果不可能,我可以让所有函数都接受相同的参数队列
- 如何无限期地启动工作线程。我不确定应该在哪里为(;;)创建
public enum DatabaseState
{
Empty = 0,
Learning = 1,
Updating = 2,
Stable = 3,
Exiting = 4
};
public class NetworkDB
{
public Dictionary<string, NetworkDevice> database;
private Queue<Action<NetworkDevice>> jobs;
private string _community;
private string _ipaddress;
private Object _statelock = new Object();
private DatabaseState _state = DatabaseState.Empty;
private readonly int workers = 4;
private Object _threadswaitinglock = new Object();
private int _threadswaiting = 0;
public Dictionary<string, NetworkDevice> Database { get => database; set => database = value; }
public NetworkDB(string community, string ipaddress)
{
_community = community;
_ipaddress = ipaddress;
database = new Dictionary<string, NetworkDevice>();
jobs = new Queue<Action<NetworkDevice>>();
}
public void Start()
{
NetworkDevice nd = SNMP.GetDeviceInfo(new IpAddress(_ipaddress), _community);
if (nd.Status > NetworkDeviceStatus.Unknown)
{
database.Add(nd.Id, nd);
_state = DatabaseState.Learning;
nd.Update(this); // The first job is done by the main thread
for (int i = 0; i < workers; i++)
{
Thread t = new Thread(JobRemove);
t.Start();
}
lock (_statelock)
{
if (_state == DatabaseState.Learning)
{
Monitor.Wait(_statelock);
}
}
lock (_statelock)
{
if (_state == DatabaseState.Updating)
{
Monitor.Wait(_statelock);
}
}
foreach (KeyValuePair<string, NetworkDevice> n in database)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(n.Value.Name + ".txt")
{
file.WriteLine(n);
}
}
}
}
public void JobInsert(Action<NetworkDevice> func, NetworkDevice nd)
{
lock (jobs)
{
jobs.Enqueue(item);
if (jobs.Count == 1)
{
// wake up any blocked dequeue
Monitor.Pulse(jobs);
}
}
}
public void JobRemove()
{
Action<NetworkDevice> item;
lock (jobs)
{
while (jobs.Count == 0)
{
lock (_threadswaitinglock)
{
_threadswaiting += 1;
if (_threadswaiting == workers)
Monitor.Pulse(_statelock);
}
Monitor.Wait(jobs);
}
lock (_threadswaitinglock)
{
_threadswaiting -= 1;
}
item = jobs.Dequeue();
item.Invoke();
}
}
public bool NetworkDeviceExists(NetworkDevice nd)
{
try
{
Monitor.Enter(database);
if (database.ContainsKey(nd.Id))
{
return true;
}
else
{
database.Add(nd.Id, nd);
Action<NetworkDevice> action = new Action<NetworkDevice>(UpdateDeviceInfo);
jobs.Enqueue(action);
return false;
}
}
finally
{
Monitor.Exit(database);
}
}
//Job1 - Learning -> Update device info
public void UpdateDeviceInfo(NetworkDevice nd)
{
nd.Update(this);
try
{
Monitor.Enter(database);
nd.Status = NetworkDeviceStatus.Self;
}
finally
{
Monitor.Exit(database);
}
}
//Job2 - Updating -> After Learning, create links between neighbours
private void UpdateLinks()
{
}
}
公共枚举数据库状态
{
空=0,
学习=1,
更新=2,
稳定=3,
退出=4
};
公共类网络数据库
{
公共词典数据库;
专用队列作业;
私人字符串(u)社区;;
私有字符串\u ipaddress;
私有对象_statelock=新对象();
私有数据库状态_state=DatabaseState.Empty;
私有只读int-workers=4;
私有对象_threadswaitinglock=新对象();
私有int_threadswaiting=0;
公共字典数据库{get=>Database;set=>Database=value;}
公共网络数据库(字符串社区、字符串IP地址)
{
_社区=社区;
_IP地址=IP地址;
数据库=新字典();
作业=新队列();
}
公开作废开始()
{
NetworkDevice nd=SNMP.GetDeviceInfo(新IpAddress(_IpAddress),_community);
如果(nd.Status>网络设备状态未知)
{
添加(nd.Id,nd);
_状态=数据库状态。学习;
Update(this);//第一个作业由主线程完成
for(int i=0;i更新设备信息
public void UpdateDeviceInfo(网络设备nd)
{
更新(本);
尝试
{
进入(数据库);
nd.Status=NetworkDeviceStatus.Self;
}
最后
{
监控退出(数据库);
}
}
//作业2-更新->学习后,在邻居之间创建链接
私有void UpdateLinks()
{
}
}
您的最佳选择似乎是使用BlockingCollection而不是Queue类。它们在FIFO方面的行为实际上是相同的,但BlockingCollection会让您的每个线程阻塞,直到可以通过调用GetConsumingEnumerable或Take获取某个项目。下面是一个完整的示例
至于包含参数,您似乎可以使用closure来封装网络设备本身,然后将操作而不是操作排入队列一个
阻止集合
是否符合您的需要?不同的数据库状态
的确切含义是什么?数据库状态的可能副本是当前状态。如果无法访问第一个设备。学习时正在查找每个设备路由表并为每个邻居跳转。更新后,用于创建设备之间的链接。我选择为此创建状态,因为只有在了解所有关于邻居的信息后,我才知道哪个neigbhour接口用于与当前设备的链接。退出ng是我给ev发信号的地方