in reply to Re^7: how to change process & thread priority on Win32 ?
in thread how to change process & thread priority on Win32 ?

I need to change both Process Priority and Thread Priority - I've already managed to change Process Priority using SetPriorityClass. So I'm working on changing the Thread Priority. I think my problem up to now has been my vagueness / misunderstandingson terminology - this was not helped by my using Win32::Process::Info to dump all the system process details - it gives Handle and ProcessId with same value, and I assumed Handle meant Thread Handle, and that it was the same as Process Id if the process only had a single thread (i.e. I thought Handle == PID == TID).
But with your detailed explanation of terminology I am now a little closer to Enlightenment. As I see it now, to change a thread priority :-
I need to generate a Duplicate Handle from within the running process.
Use this duplicate handle from within Perl to change the Thread Priority of the original thread.
I'll go away and use the info I now have to make it work. Many thanks for your patience.
  • Comment on Re^8: how to change process & thread priority on Win32 ?

Replies are listed 'Best First'.
Re^9: how to change process & thread priority on Win32 ?
by BrowserUk (Patriarch) on Dec 10, 2005 at 08:32 UTC
    this was not helped by my using Win32::Process::Info to dump all the system process details - it gives Handle and ProcessId with same value, and I assumed Handle meant Thread Handle, and that it was the same as Process Id if the process only had a single thread (i.e. I thought Handle == PID == TID).

    I'm not sure why the 'handle' key returned from Win32::Process::Info is so labelled. From a quick inspection, it appears to the the same value as the 'ProcessId' in every case. It just appears to be a duplicate.

    As I see it now, to change a thread priority :-
  • I need to generate a Duplicate Handle from within the running process.
  • Use this duplicate handle from within Perl to change the Thread Priority of the original thread.
    1. As far as I am aware, there is no mechanism for obtaining a handle to a thread within another process.

      Update: It is possible to obtain a handle to a thread within another process, namely OpenThread(), but you must have a Win32 native TID (not a threads module TID).

    2. Unless you have the source code for all the processes you are trying to affect, you will not be able to use DuplicateHandle() within those processes(*).

      Even if you do have the sources, you wouldn't be able to generate a duplicate thread handle for your Perl script's use without having a process handle to the Perl process. Catch22.

      And even if you arrange for all the processes you wish to modify to look for your Perl script and generate a duplicate for it, you would still need to communicate those to your Perl script.

    3. Adjusting the priority of another process' threads is a really "Bad Idea".

      Actually, adjusting another process' priority class is not a great idea either, unless it is just a temporary measure and you set it back to it former value fairly soon afterwards.

      Even setting the priority (class) of your own process or threads to non-default values is not recommended unless you have very well thought through reasons for doing so, and those threads or processes are written to do tasks that require it, and are aware of their status.

      Eg. If you have a process that needs to respond very quickly to an event when it occurs, then running the thread waiting (on a semaphore or similar sleep-till-it happens mechanism--not polling!), for that event, then setting it's priority higher than normal can work. But once it becomes unblocked, it should either do what it has to do very quickly and go back to blocking, by handing the work off to a normal priority thread if it will take any time, or by dropping it's priority before doing the work.

      Multi-threaded processes rely upon the relative priority of their threads being well balanced commensurate with the types of work each thread is charged with doing. If you go around adjusting those priorities without understanding the balance required, you will probably render the processes, and possibly your system, defective or non-functional.

    So the questions are: Why do you want to do this? What are you trying to achieve?

    (*)Actually, there is a mechanism that involves injecting a thread into the other process using CreateRemoteThread(). This requires exceptional privileges, and is normally reserved for Debugger programs.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I need to control the priorities of various longrunning jobs - some of which kick off threads with nonstandard priority settings which cause some to hog the cpu, others to get none - this Perl utility is intended to keep them running at uniform settings.
      I have been given the source of a C program that adjusts thread priority. The relevant code :-
      HANDLE hProcessSnap = NULL; BOOL bRet = FALSE; THREADENTRY32 te32 = {0}; // Take a snapshot of all processes in the system. hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) return (FALSE); // Fill in the size of the structure before using it. te32.dwSize = sizeof(THREADENTRY32); // Get first process information Thread32First(hProcessSnap, &te32) // get the thread priority HANDLE hThread; hThread = OpenThread(THREAD_SET_INFORMATION|THREAD_QUERY_INFORMATI +ON, FALSE, te32.th32ThreadID); // set new priority class if (SetThreadPriority(hThread, threadPriority) != TRUE) { cerr << "SetThreadPriority() "; printError(); } CloseHandle(hThread);
      I can't see why the last parameter to CreateToolhelp32Snapshot is 0, as that means current process Id, in this case Perl - I would have thought this should be PID of the process whose thread I want to change. ??
      I converted the above to Perl calls to Win32::API as follows :-
      $pid = 952; # 952 is a running job pid use threads; use threads::shared; use Win32::API; Win32::API->Import( 'Kernel32', q[ DWORD GetLastError( ) ] ); Win32::API->Import( 'Kernel32', q[ HANDLE CreateToolhelp32Snapshot( DWORD dwFlags, DWORD th32Pr +ocessID ) ] ); $hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, $pid); + print "hProcessSnap = $hProcessSnap \n";
      580 output, presumably an open handle to the snapshot
      Win32::API->Import( 'Kernel32', q[ BOOL Thread32First( HANDLE hSnapshot, THREADENTRY32 lpte)] ); $retcode = GetLastError(); print "import threadfirst error was $retcode \n";
      WARNING Unknown parameter type THREADENTRY32 ??
      0 output, import OK ??
      The following is my attempt to define the C THREADENTRY32 structure - not to sure about this.
      # typedef for THREADENTRY32 typedef Win32::API::Struct AA => qw{ DWORD dwSize; DWORD cntUsage; DWORD th32ThreadID; DWORD th32OwnerProcessID; LONG tpBasePri; LONG tpDeltaPri; DWORD dwFlags; }; my $Point = Win32::API::Struct->new( AA ); $Point->{dwSize} = 24; ##$size=Win32::API::Struct->sizeof(AA); ##always returns 0. ?? Thread32First($hProcessSnap, LPAA); $retcode = GetLastError(); print "threadfirst error was $retcode \n";
      error code 24 is output, indicating incorrect command length.
      Acording to the Win32::API::Struct Pod, LPAA is a pointer to AA generated automatically by Win32::API::Struct, but I don't think it's getting a correct address. Any Perl way to get the address of AA to pass to Thread32First ?
      The rest of the Perl code will be :-
      Win32::API->Import( 'Kernel32', q[HANDLE OpenThread( DWORD dwDesiredAc +cess, BOOL bInheritHandle, DWORD dwThreadId) ] ); $hThread = OpenThread(THREAD_SET_INFORMATION|THREAD_QUERY_INFORMATION, FALSE, $point->{th32ThreadID}); Win32::API->Import( 'Kernel32', q[ BOOL SetThreadPriority( HANDLE hThr +ead, int nPriority ) ] ); SetThreadPriority( hThread, $threadpriority );
      But I'm stuck at Thread32First

        Take a look at the prototype for OpenThread():

        HANDLE OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId );

        The only parameter there for identifying the thread to open, is the dwThreadId. Remember I described ThreadId as process unique--not system unique. Basically, OpenThread() can only be used to obtain handles to threads within the process from which it is called.

        To be able to do this across process boundaries, it would need to also take a PID, so that you could ask it to give you a handle to 'this thread', within 'this process'. Without that, it will always attempt to get a handle to the specified TID within the current process.

        As I said, I am not aware of any API for obtaining a thread handle to a thread in another process.

        You could try the CreateRemoteThread() API to inject a thread into the process you trying to alter, and run the CreateSnapshot/OpenThread/SetThreadPriority from there, but from experience, the first of those is not an easy API to make work. Even if you get that going, I am not sure that it would allow a thread created by another process to mess with priorities.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        I need to control the priorities of various longrunning jobs - some of which kick off threads with nonstandard priority settings which cause some to hog the cpu

        Hmm. Remember that thread priorities are relative to the process' priority class. If you have a process that is hogging the cpu, it will be enough to drop it priority class below that of the other processes to prevent it from usurping their timeslices.

        A THREAD_PRIORITY_HIGHEST thread in a BELOW_NORMAL_PRIORITY_CLASS process, will never starve a THREAD_PRIORITY_NORMAL thread in a NORMAL_PRIORITY_CLASS process. Ie. You should be able to disarm any process that is starving other processes by only adjusting it's priority class.

        It may cause that process to be starved of cpu until the other processes have completed, but that simply means that whomever is boosting their priority to the detriment of others will rapidly learn that their antisocial behaviour will not be tolorated and will cease to do it.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.