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規格書上提到
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"和"處理選項"的方法來套
/// <summary>
/// Process option
/// </summary>
public enum ProcessEnum
{
Suspend = 0, Resume, Print, Kill
}
/// <summary>
/// Control the process
/// </summary>
/// <param name="PID">The pid.</param>
/// <param name="OPTION">The option.</param>
/// <returns></returns>
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。