Mainframe主机环境中当批次执行太久,想释放CPU资源给其他批次执行时,我们会调整较低等级的Priority或者将这支JOB Cancel,最近搜寻了在开放系统.NET环境的作法。
笔记一下需求及解决方案:
由外部Process发出
- 暂停批次
- 被暂停的批次继续执行
- 取消批次
1.Process vs Thread,先了解处理进程与执行序基本概念,刚好批次都是一个可执行文件,执行时就一个Process,然后视程序功能以单执行序或多执行序执行。
https://en.wikipedia.org/wiki/Thread_(computing)
2.Process内建的功能: 具备kill() 砍job 取消批次功能,但少了临时暂停 和 暂停工作继续执行
不过thread 执行序方法则有
如果要砍job,kill()很适合;但要暂停手边的工作,待会再继续执行,看起来要从thread这一层下手,但MSDN中的方法被标示为过时,原因是担心thread lock,但我们还是希望可以有这个功能,继续匍匐前进。
3.现成增加Process Extension解决方案: http://stackoverflow.com/questions/71257/suspend-process-in-c-sharp
果然在stackoverflow找到答案,利用调用Kernel32.lib中的SuspendThread及ResumeThread功能来解决
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class ProcessExtension
{
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
public static void Suspend(this Process process)
{
foreach (ProcessThread thread in process.Threads)
{
var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
{
break;
}
SuspendThread(pOpenThread);
}
}
public static void Resume(this Process process)
{
foreach (ProcessThread thread in process.Threads)
{
var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
{
break;
}
ResumeThread(pOpenThread);
}
}
public static void Print(this Process process)
{
Console.WriteLine("{0,8} {1}", process.Id, process.ProcessName);
}
}
[Flags]
public enum ThreadAccess : int
{
TERMINATE = (0x0001),
SUSPEND_RESUME = (0x0002),
GET_CONTEXT = (0x0008),
SET_CONTEXT = (0x0010),
SET_INFORMATION = (0x0020),
QUERY_INFORMATION = (0x0040),
SET_THREAD_TOKEN = (0x0080),
IMPERSONATE = (0x0100),
DIRECT_IMPERSONATION = (0x0200)
}
Win kernel api规格书上提到
suspend方法If the function succeeds, execution of the specified thread is suspended and the thread's suspend count is incremented.
Suspending a thread causes the thread to stop executing user-mode (application) code.
The ResumeThread function decrements a thread's suspend count. When the suspend count is decremented to zero,
the execution of the thread is resumed.
显示process id及process name
4.撰写一个输入"PID"和"处理选项"的方法来套
///
/// Process option
///
public enum ProcessEnum
{
Suspend = 0, Resume, Print, Kill
}
///
/// Control the process
///
/// The pid.
/// The option.
///
public string ctrlP(int PID, ProcessEnum OPTION)
{
try
{
var p = Process.GetProcessById(PID);
if (p != null)
{
switch (OPTION)
{
case ProcessEnum.Suspend:
p.Suspend();
break;
case ProcessEnum.Resume:
p.Resume();
break;
case ProcessEnum.Print:
p.Print();
break;
case ProcessEnum.Kill:
p.Kill();
break;
}
return string.Format("00:{0}({1})", PID, OPTION);
}
else
{
return string.Format("23:{0}({1})", PID, OPTION);
}
}
catch (Exception e)
{
using (StreamWriter sw = File.AppendText(LogURL)) { sw.WriteLine("{0:u} Job Error:{1}({2}), {3}", DateTime.Now, PID, OPTION, e.ToString()); }
return string.Format("99:{0}", e.ToString());
}
}
5.执行中的批次程序 (状态:执行中),他是1支每5秒写1笔log的测试程序,总共要写10次log。
6.调用Suspend()后,状态-(已暂止),从数据库观察,程序已经写了3次log。
调用Resume()后,批次也继续将剩余的7次log工作完成了,目前测试单执行序process 暂止都很正常。
之后有时间继续来测试多执行序的process 或 改用powershell cmdlet操作 process。
原文:大专栏 [.NET] Suspend Process 暂停批次执行