一、故事线
当已经有一个完整的项目方案,突然提出需要增加功能支持并行的需求时,通常考虑项目中模块是否支持并行,比如使用了单例模式时,又要模块区分,单例模块将需要修改等等问题。
此时,可以采用启动器方式实现,该方式的优点是:已完成项目只需要增加启动标识的相关功能即可,其他功能可直接使用,极大缩短功能并行的开发周期。
二、启动器
我的项目中需要的启动器本身也是一个winform程序,其中包含多个按钮对应并行多个并行程序,点击按钮后打开一个程序副本。
需要考虑的问题:
1 每个副本只允许执行一次,比如支持四个副本,那么一共只能有一个副本(当然,这是我的需求,如果不考虑可以不做限制),需要做副本检查的方案。
2 单个副本内的项目静态变量是否共享问题。如果共享的话这个方案将失效。经过验证是独立的。
3 如何启动新的exe程序。
三、启动器实现
1 程序可以多开,但启动器必然只能运行一个,此时使用Mutex实现:
var mutex = new Mutex(true, key, out result);
- key为一个唯一标识
- result为结果,如果为false,表示已标记,如果只有你的程序进行该key的设置,那么你的程序已经启动了。
2 启动器中,打开副本程序,使用以下代码:
Process myprocess = new Process(); ProcessStartInfo startInfo = new ProcessStart(path, args); myprocess.StartInfo = startInfo; myprocess.StartInfo.UseShellExecute = false; myprocess.Start();
args为string类型的变量,如果你还熟悉以下代码,那么应该args的第一个元素即为当前的args变量。
path为打开程序路径,注意必须是绝对路径。
/// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main(string[] args) { //... }
3 启动器中的副本检查方案,由于单个副本只能打开一次,启动器需要持续跟进副本是否已经终结,并允许用户重启开启。我采用的方案是通过ini配置文件实现:
FileTooler.IniWriteValue("STARTUP", $"CHN{index}", "1", CONFIG_PAHT);
FileTooler.IniWriteValue是我封装的ini方法,具体ini操作参照以下内容:
[DllImport("kernel32")] private static extern long WritePrivateProfileString(string section , string key , string val , string filePath); [DllImport("kernel32")] private static extern int GetPrivateProfileString(string section , string key , string def , StringBuilder retVal , int size , string filePath);
这里的关键是第二个参数$"CHN{index}",index对应副本编号,"1"表示开启。
同理,对应的副本程序关闭时,应当调用以下代码更新ini文件。
FileTooler.IniWriteValue("STARTUPA20", $"CHN{index}", "0", CONFIG_PAHT);
除了开始副本时和结束副本时设置ini文件外,需要增加一个timer进行持续检查:
private void timer1_Tick(object sender, EventArgs e) { for (int i = 0; i < 4; i++) { var chk = Syscan.File.FileTooler.IniReadValue("STARTUPA20", $"CHN{index}", CONFIG_PAHT)=="1"; btns[i].Text = $"通道{index}" + (chk? " 已启动" : ""); btns[i].Enabled = !chk; } }
这里可以看出对应的通道设置的是button控件,通过enable和文字描述提醒用户是否可以重新开启。
Timer的使用也不再这里赘述,不了解的请移步:
https://msdn.microsoft.com/zh-cn/library/system.windows.forms.timer.aspx
四、其他
在这个框架下如果想支持部分数据共享,最简单的方案是把共享部分放在一个数据库中,非共享单独分放即可。
五、总结
该方案主要涉及的技术点包括:
1 基于Mutex单一进程检查
2 ini文件读写
3 Process方式启动新程序
4 Timer的使用
至此启动器方案确定,如有任何疑问可以留言。