1

Consider, I have an .NET Core app that will spawn many proccesses. I'd like to throttle to use max 10% of CPU and X MB of memory. In full .net framework I could do the following: https://stackoverflow.com/a/33343901/5417374

public static class ProcessManager
{
    [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)
    }

    [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);

    [DllImport("kernel32.dll")]
    static extern int CloseHandle(IntPtr hThread);

    public static void ThrottleProcess(int processId, double limit)
    {
        var process = Process.GetProcessById(processId);
        var processName = process.ProcessName;
        var p = new PerformanceCounter("Process", "% Processor Time", processName);
        while (true)
        {
            var interval = 100;
            Thread.Sleep(interval);

            var currentUsage = p.NextValue() / Environment.ProcessorCount;
            if (currentUsage < limit) continue;
            var suspensionTime = (currentUsage-limit) / currentUsage * interval;
            SuspendProcess(processId);
            Thread.Sleep((int)suspensionTime);
            ResumeProcess(processId);
        }
    }

    private static void SuspendProcess(int pid)
    {
        var process = Process.GetProcessById(pid);

        if (process.ProcessName == string.Empty)
            return;

        foreach (ProcessThread pT in process.Threads)
        {
            IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);

            if (pOpenThread == IntPtr.Zero)
            {
                continue;
            }

            SuspendThread(pOpenThread);

            CloseHandle(pOpenThread);
        }
    }

    private static void ResumeProcess(int pid)
    {
        var process = Process.GetProcessById(pid);

        if (process.ProcessName == string.Empty)
            return;

        foreach (ProcessThread pT in process.Threads)
        {
            IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);

            if (pOpenThread == IntPtr.Zero)
            {
                continue;
            }

            var suspendCount = 0;

            do
            {
                suspendCount = ResumeThread(pOpenThread);
            } while (suspendCount > 0);

            CloseHandle(pOpenThread);
        }
    }
}

But .NET Core (that could be run on linux as well) it could not work. It is possible to achevie it somehow?

pwas
  • 3,225
  • 18
  • 40
  • 4
    This is not a good thing to do even in the full .NET Framework. The runtime can't guarantee things will keep running correctly if you suspend threads like this, as it completely bypasses the CLR's thread management, possibly leading to things like timeouts on locks. In Windows, there's a cleaner solution in the form of [job objects](https://msdn.microsoft.com/library/windows/desktop/ms684161). In Linux, there's cgroups, but I'm not familiar with the details on that. In either case, you'll need an OS-specific mechanism beyond what .NET Core can offer you natively. – Jeroen Mostert Oct 24 '17 at 12:02
  • Agreed 100%. There's better ways to control this. – Chris Pratt Oct 24 '17 at 12:43
  • 1
    Typical approach today is to run all such in a container (or a few containers) where you can fully control the resources used at container level. – Lex Li Oct 24 '17 at 21:49

0 Answers0