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

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

Replies are listed 'Best First'.
Re^11: how to change process & thread priority on Win32 ?
by BrowserUk (Patriarch) on Dec 11, 2005 at 09:47 UTC

    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 hear you. But from what I can understand from the MSDN documentation the sequence of API calls required is :-
      • take a snapshot of currently executing processes in the system using CreateToolhelp32Snapshot
      • walk through the list recorded in the snapshot using Process32First and Process32Next, until we find the PID we want.
      • get the first (and in this case only) thread details for list recorded in the snapshot using Thread32First
      • use SetThreadPriority to modify the thread.
      Looks like there is no direct access to the thread of the PID I want, but by reading thru the whole list we can get there.
      I'm no expert, but the difficulty is getting Win32::API to let me make all the calls I need to. At the moment I'm getting error code 24 (incorrect length) on Process32First. My code :-
      $pid = 952; # 952 is a running job pid use threads; use threads::shared; use Win32::API; Win32::API->Import( 'Kernel32', q[ DWORD GetLastError( ) ] ); $retcode = Win32::API->Import( 'Kernel32', q[ HANDLE CreateToolhelp32Snapshot ( DWORD dwFlags, DWORD th32ProcessID ) ] ); print "import CreateToolhelp32Snapshot code $retcode \n"; $hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); $retcode = GetLastError(); print "CreateToolhelp32Snapshot error code $retcode \n"; print "hProcessSnap = $hProcessSnap \n"; # typedef for PROCESSENTRY32 typedef Win32::API::Struct AA => qw{ DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; DWORD cntThreads; DWORD th32ParentProcessID; LONG pcPriClassBase; DWORD dwFlags; TCHAR szExeFile[MAX_PATH]; }; $retcode = Win32::API->Import( 'Kernel32', q[BOOL Process32First( + HANDLE hSnapshot, LPAA lppe ) ] ); print "import process32first code $retcode \n"; $Point = Win32::API::Struct->new( 'AA' ); $Point->{dwSize}=Win32::API::Struct::sizeof( $Point ); Process32First($hProcessSnap, $Point); $retcode = GetLastError(); print "process32first error $retcode \n"; $retcode = Win32::API->Import( 'Kernel32', q[BOOL Process32Next( + HANDLE hSnapshot, LPAA lppe ) ] ); print "import process32next code $retcode \n"; until ( $Point->th32OwnerProcessID == $pid ) { Process32Next($hProcessSnap, $Point); $retcode = GetLastError(); print "process32next error code $retcode \n"; }
      I get error 24 (incorrect length) on Process32First.
        Looks like there is no direct access to the thread of the PID I want, but by reading thru the whole list we can get there.

        But you are still missing the point. The information available in the THREADENTRY32 structure return by Thread32First/Next() calls does not include a thread handle, only a thread ID.

      • use SetThreadPriority to modify the thread.
      • SetThreadPriority() requires a thread handle as it's first parameter, and there is no way to go from a thread ID to a thread handle.

        Ergo. Even if you solve your current problem with Process32First, you will arrive at a place where you still cannot do what you are trying to do.


        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.
Re^11: how to change process & thread priority on Win32 ?
by BrowserUk (Patriarch) on Dec 11, 2005 at 10:08 UTC
    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.