C# 单实例.NET核心应用程序(或使crontab仅运行我的应用程序的1个实例)

C# 单实例.NET核心应用程序(或使crontab仅运行我的应用程序的1个实例),c#,.net,linux,cron,.net-core,C#,.net,Linux,Cron,.net Core,我想在Linux中使用crontab按时间表执行.NET核心应用程序。这是一个长时间运行的操作,如果上一次执行尚未完成,我不希望运行另一个实例。换句话说,我不希望crontab在给定的时间执行我的.NET核心应用程序的多个实例 有什么办法可以避免吗?我不想修改我的应用程序的代码。也许crontab有一个避免并发的选项。我还不是Linux专家:)可能在脚本中,而不是在程序中设置重复检查 因此,在执行程序之前,请检查“ps-ef | grep myprogramname”的输出。如果要在程序中解决它

我想在Linux中使用crontab时间表执行.NET核心应用程序。这是一个长时间运行的操作,如果上一次执行尚未完成,我不希望运行另一个实例。换句话说,我不希望crontab在给定的时间执行我的.NET核心应用程序的多个实例


有什么办法可以避免吗?我不想修改我的应用程序的代码。也许crontab有一个避免并发的选项。我还不是Linux专家:)

可能在脚本中,而不是在程序中设置重复检查


因此,在执行程序之前,请检查“ps-ef | grep myprogramname”的输出。

如果要在程序中解决它,可以在System.Diagnostics.Process.GetProcesses中循环所有进程,并检查任何进程可执行路径是否以文件名结尾

[System.STAThread]
static void Main(string[] args)
{
    foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
    {
        if (p.MainModule.FileName.EndsWith("bla.exe", System.StringComparison.CurrentCultureIgnoreCase))
            return;
    }
    [...]
}
否则,让脚本在/var/run中设置一个值,并检查该文件是否存在。如果您的程序以任何方式退出,该文件将被删除

此外,还要解决运行时间长的问题。 程序通常不会花那么长时间。 在我看来,你好像做错了什么,除非你确实在处理几GB的数据

如果MainModule返回dotnet,您还可以读取link proc/pid/exe/(Linux或BSD)或/proc/self/exe(仅限Linux)

或者,如果这也只生成dotnet,则可以读取命令行参数(/proc/pid/cmdline-linux only):

publicstaticbyte[]ReadReallyAllBytes(字符串文件名)
{
字节[]retValue=null;
使用(System.IO.FileStream fs=System.IO.File.OpenRead(文件名))
{
字节[]缓冲区=新字节[System.Environment.SystemPageSize];
List byteList=新列表();
int-ct=0;
而((ct=fs.Read(buffer,0,buffer.Length))>0)
{
对于(int i=0;i
现在,如果MainModule是dotnet,请检查命令行参数列表是否包含dll/exe。
此外,如果您进行发布构建(独立-无共享框架),那么它应该与MainModule一起工作

我终于使用了一个可供Raspbian使用的小工具:flock

在我的crontab配置文件中,我将:

flock -n /tmp/importer.lock dotnet ~/Desktop/Importer/Plugin.Clm.Importer.Console.dll
flock似乎在运行时编写了一个锁文件,并执行该命令。它再次执行,并且锁文件在那里,它只是失败了。完成后,它将释放该文件,允许再次调用该文件


简而言之:它充当一个信号量:)

对于那些想要从代码中检查实例的人,您可以像这样使用命名互斥

const string mutexName = @"Global\appName";

var mutex = new Mutex(true, mutexName, out var createdNew);

if (!createdNew)
{
    Console.WriteLine(mutexName + " is already running! Exiting the application.");
    return;
}

请确保您的互斥体名称以
“Global\”

开头,有时长时间运行的进程是由于一天中多次检查造成的,检查之间会有停顿(即如果结果处理数据,则每小时进行此检查)@hellyale:因为cron调用您的进程,即每小时,程序完成后不需要继续运行。。。否则,您就不需要cron。您的第一个解决方案将无法工作,因为
Process.MainModule.FileName
对于每个网络核心应用程序都始终是“dotnet”。@xneg:正确的方法:readlink/proc//exe(Linux,BSD)或readlink/proc/self/exe(仅限Linux)@stefanstieger如何在代码中应用此方法。你能举个例子吗?这很好+1
Mutex
具有线程亲和力,这意味着您不能将其与
async
代码一起使用,因此如果您可以使用它,
Semaphore
是一个更好的选择(例如,Linux目前不支持名为
Semaphores
)@13xfore在程序开始时执行检查时,您真的需要异步代码吗?@xneg当您使用新的
async Task Main(){}
签名时,它会很有帮助
flock -n /tmp/importer.lock dotnet ~/Desktop/Importer/Plugin.Clm.Importer.Console.dll
const string mutexName = @"Global\appName";

var mutex = new Mutex(true, mutexName, out var createdNew);

if (!createdNew)
{
    Console.WriteLine(mutexName + " is already running! Exiting the application.");
    return;
}