v2rayN
v2rayN copied to clipboard
恢复使用pnputil的方式清除sing-tun可能残留下的wintun设备驱动
如果只是不希望引入第三方库的话,那使用pnputil传入instance ID参数也能实现精准匹配并删除本程序启动的singbox残留下的wintun设备驱动。原来是通过匹配deviceid的方式清除设备驱动,个人觉得这样有点一刀切了,因为这样会清除所有使用Wintun API创建的tun设备,而不管是不是本程序启动的singbox创建的。 还有就是我打算添加全局热键开启和关闭Tun mode的功能,所以加固了一下在比较频繁执行LoadCore方法的情况下的稳定性。
什么情况下会频繁调用 LoadCore
?
如果要防止并发调用LoadCore
,只需要加一个lock应该就行了,不需要这么复杂吧?
什么情况下会频繁调用
LoadCore
? 如果要防止并发调用LoadCore
,只需要加一个lock应该就行了,不需要这么复杂吧?
刚刚看了我这代码确实是有点问题,我本意是想实现如果在LoadCore执行过程中如果有一个或多个线程在调用它的时候,只需再执行一次,然后直接返回那些调用,我等会儿把代码修正下
如果有
什么情况下会频繁调用
LoadCore
? 如果要防止并发调用LoadCore
,只需要加一个lock应该就行了,不需要这么复杂吧?刚刚看了我这代码确实是有点问题,我本意是想实现如果在LoadCore执行过程中如果有一个或多个线程在调用它的时候,只需再执行一次,然后直接返回那些调用,我等会儿把代码修正下
如果多个线程调用 LoadCore,应该让它们都执行一次,在执行时lock就可以了,如下面的代码
private static readonly object loadLock = new();
public void LoadCore()
{
var node = ConfigHandler.GetDefaultServer(_config);
if (node == null)
{
ShowMsg(false, ResUI.CheckServerSettings);
return;
}
lock (loadLock)
{
string fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
{
ShowMsg(false, msg);
}
else
{
ShowMsg(false, msg);
ShowMsg(true, $"{node.GetSummary()}");
CoreStop();
if (_config.tunModeItem.enableTun)
{
Thread.Sleep(1000);
Utils.RemoveTunDevice();
}
CoreStart(node);
//In tun mode, do a delay check and restart the core
if (_config.tunModeItem.enableTun)
{
Observable.Range(1, 1)
.Delay(TimeSpan.FromSeconds(15))
.Subscribe(x =>
{
{
if (_process == null || _process.HasExited)
{
CoreStart(node);
ShowMsg(false, "Tun mode restart the core once");
Logging.SaveLog("Tun mode restart the core once");
}
}
});
}
}
}
}
如果有
什么情况下会频繁调用
LoadCore
? 如果要防止并发调用LoadCore
,只需要加一个lock应该就行了,不需要这么复杂吧?刚刚看了我这代码确实是有点问题,我本意是想实现如果在LoadCore执行过程中如果有一个或多个线程在调用它的时候,只需再执行一次,然后直接返回那些调用,我等会儿把代码修正下
如果多个线程调用 LoadCore,应该让它们都执行一次,在执行时lock就可以了,如下面的代码
private static readonly object loadLock = new(); public void LoadCore() { var node = ConfigHandler.GetDefaultServer(_config); if (node == null) { ShowMsg(false, ResUI.CheckServerSettings); return; } lock (loadLock) { string fileName = Utils.GetConfigPath(Global.CoreConfigFileName); if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0) { ShowMsg(false, msg); } else { ShowMsg(false, msg); ShowMsg(true, $"{node.GetSummary()}"); CoreStop(); if (_config.tunModeItem.enableTun) { Thread.Sleep(1000); Utils.RemoveTunDevice(); } CoreStart(node); //In tun mode, do a delay check and restart the core if (_config.tunModeItem.enableTun) { Observable.Range(1, 1) .Delay(TimeSpan.FromSeconds(15)) .Subscribe(x => { { if (_process == null || _process.HasExited) { CoreStart(node); ShowMsg(false, "Tun mode restart the core once"); Logging.SaveLog("Tun mode restart the core once"); } } }); } } } }
让它们都执行一次在大多数情况下是有必要的,但是对于这个方法而言总是最后一次的执行才是有意义的,让每个阻塞的线程都执行一次可能会产生不必要的开销。 特别是在阻塞线程的队列较长的情况下,队列最后的线程要等很久,方法才能返回,这样有可能还会影响到使用的体验。 我这样做就是尽量避免无意义的重复调用,而且不管阻塞的线程队列有多长,每个线程最多只需等待在执行此方法没有遇到阻塞情况的执行时间的两倍。 现在我把代码修正了,你再看看就知道了
实际上用户是无法并发操作LoadCore,存在并发只是在更新core等自动功能上,所以发生的机率非常低 为一个低概率事件写过于复杂的逻辑是不必要的,所以如果要处理LoadCore代码,暂只接受 lock 这种简单的方式
``
实际上用户是无法并发操作LoadCore,存在并发只是在更新core等自动功能上,所以发生的机率非常低 为一个低概率事件写过于复杂的逻辑是不必要的,所以如果要处理LoadCore代码,暂只接受 lock 这种简单的方式
用户操作并发LoadCore的可能性有很多,因为目前vm的LoadCore的方法是异步的。 `public void Reload() { BlReloadEnabled = false;
LoadCore().ContinueWith(task =>
{
TestServerAvailability();
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
BlReloadEnabled = true;
}));
});
} private async Task LoadCore() { await Task.Run(() => { _coreHandler.LoadCore();
//ConfigHandler.SaveConfig(_config, false);
ChangeSystemProxyStatus(_config.sysProxyType, false);
});
} this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables);` 对于能操作到CoreHandler.LoadCore()的用户控件,只对主窗体的”重启服务“按钮做了同步机制 这就意味着如果用户在频繁的切换活动服务器或Tun模式状态,亦或增删改代理节点等等情况下就会出现并发调用CoreHandler.LoadCore()方法