> Thread Scheduling, Priorities, and Affinities
 FrontPage|FindPage|TitleIndex|RecentChanges|UserPreferences U E D R S P I M H RSS

Á¤¸®Á¤¸®/°øºÎ¸Þ¸ðÀåÁ¤¸®/KernelObjectsÁ¤¸®/ThreadBasicsÁ¤¸®/ThreadPooling › Á¤¸®/ThreadSchedulingAndPrioritiesAndAffinities
<!> UnderConstruction

Contents:
1 Thread Scheduling, Priorities, and Affinities
2 Suspending and Resuming a Thread


1 Thread Scheduling, Priorities, and Affinities #



2 Suspending and Resuming a Thread #


DWORD ResumeThread( HANDLE hThread );

DWORD SuspendThread( HANDLE hThread );

3 Suspending and Resuming a Process #


VOID SuspendProcess( DWORD dwProcessID, BOOL fSuspend )
{
    // Get the list of threads in the system.
    HANDLE hSnapshot = CreateToolhelp32Snapshot(
        TH32CS_SNAPTHREAD, dwProcessID );

    if( hSnapshot != INVALID_HANDLE_VALUE ) {
        // Walk the list of threads.
        THREADENTRY32 te = { sizeof( te ) };
        BOOL fOk = Thread32First( hSnapshot, &te );
        for( ; fOk; fOk = Thread32Next( hSnapshot, &te ) ) {

            // Is this thread in the desired process?
            if( te.th32OwnerProcessID == dwProcessID ) {

                // Attempt to convert the thread ID into a handle.
                HANDLE hThread = OpenThread( THREAD_SUSPEND_RESUME,
                    FALSE, te.th32ThreadID );

                if( hThread != NULL ) {

                    // Suspend or resume the thread.
                    if( fSuspend )
                        SuspendThread( hThread );
                    else
                        ResumeThread( hThread );
                }
                CloseHandle( hThread );
            }
        }
        CloseHandle( hSnapshot );
    }
}

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

4 Sleeping #


VOID Sleep( DWORD dwMilliseconds );

5 Switching to Another Thread #


BOOL SwitchToThread();

6 A Thread's Execution Times #


// Get the current time (start time).
DWORD dwStartTime = GetTickCount();

// Perform complex algorithm here.

// Subtract start time from current time to get duration.
DWORD dwElapsedTime = GetTickCount() - dwStartTime;

BOOL GetThreadTimes(
	HANDLE hThread,
	PFILETIME pftCreationTime,
	PFILETIME pftExitTime,
	PFILETIME pftKernelTime,
	PFILETIME pftUserTime
);

Time ValueMeaning
Creation time An absolute value expressed in 100-nanosecond intervals past midnight on January 1, 1601, at Greenwich, England, indicating when the thread was created.
Exit time An absolute value expressed in 100-nanosecond intervals past midnight on January 1, 1601, at Greenwich, England, indicating when the thread exited. If the thread is still running, the exit time is undefined.
Kernel time A relative value indicating how many 100-nanosecond intervals of CPU time the thread has spent executing operating system code.
User time A relative value indicating how many 100-nanosecond intervals of CPU time the thread has spent executing application code.

__int64 FileTimeToQuadWord( PFILETIME pft )
{
    return( Int64ShllMod32( pft->dwHighDateTime, 32 ) | pft->dwLowDateTime );
}

void PerformLongOperation()
{
    FILETIME ftKernelTimeStart, ftKernelTimeEnd;
    FILETIME ftUserTimeStart,   ftUserTimeEnd;
    FILETIME ftDummy;
    __int64 qwKernelTimeElapsed, qwUserTimeElapsed,
        qwTotalTimeElapsed;

    // Get starting times.
    GetThreadTimes( GetCurrentThread(), &ftDummy, &ftDummy,
        &ftKernelTimeStart, &ftUserTimeStart );


    // Perform complex algorithm here.


    // Get ending times.
    GetThreadTimes( GetCurrentThread(), &ftDummy, &ftDummy,
        &ftKernelTimeEnd, &ftUserTimeEnd );

    // Get the elapsed kernel and user times by converting the start
    // and end times from FILETIMEs to quad words, and then subtract
    // the start times from the end times.
    qwKernelTimeElapsed = FileTimeToQuadWord( &ftKernelTimeEnd ) -
        FileTimeToQuadWord( &ftKernelTimeStart );

    qwUserTimeElapsed = FileTimeToQuadWord( &ftUserTimeEnd ) -
        FileTimeToQuadWord( &ftUserTimeStart );

    // Get total time duration by adding the kernel and user times.
    qwTotalTimeElapsed = qwKernelTimeElapsed + qwUserTimeElapsed;

    // The total elapsed time is in qwTotalTimeElapsed.
}

BOOL GetProcessTimes(
	HANDLE hProcess,
	PFILETIME pftCreationTime,
	PFILETIME pftExitTime,
	PFILETIME pftKernelTime,
	PFILETIME pftUserTime
);

BOOL QueryPerformanceFrequency( LARGE_INTEGER* pliFrequency );

BOOL QueryPerformanceCounter( LARGE_INTEGER* pliCount );

class CStopwatch {
public:
    CStopwatch() { QueryPerformanceFrequency( &m_liPerfFreq ); Start(); }

    void Start() { QueryPerformanceCounter( &m_liPerfStart ); }

    __int64 Now() const     // Returns # of milliseconds since Start was called
    {
        LARGE_INTEGER liPerfNow;
        QueryPerformanceCounter( &liPerfNow );
        return ( ( ( liPerfNow.QuadPart - m_liPerfStart.QuadPart ) * 1000 )
            / m_liPerfFreq.QuadPart );
    }

private:
    LARGE_INTEGER m_liPerfFreq;     // Counts per second
    LARGE_INTEGER m_liPerfStart;    // Starting count
};

// Create a stopwatch timer (which defaults to the current time).
CStopwatch stopwatch;

// Execute the code I want to profile here.

// Get how much time has elapsed up to now.
__int64 qwElapsedTime = stopwatch.Now();

// qwElapsedTime indicates how long the profiled code
// executed in milliseconds.

7 Putting the Context in Context #


typedef struct _CONTEXT {

    //
    // The flags values within this flag control the contents of
    // a CONTEXT record.
    //
    // If the context record is used as an input parameter, then
    // for each portion of the context record controlled by a flag
    // whose value is set, it is assumed that that portion of the
    // context record contains valid context. If the context record
    // is being used to modify a threads context, then only that
    // portion of the threads context will be modified.
    //
    // If the context record is used as an IN OUT parameter to capture
    // the context of a thread, then only those portions of the thread's
    // context corresponding to set flags will be returned.
    //
    // The context record is never used as an OUT only parameter.
    //

    DWORD ContextFlags;

    //
    // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
    // set in ContextFlags.  Note that CONTEXT_DEBUG_REGISTERS is NOT
    // included in CONTEXT_FULL.
    //

    DWORD   Dr0;
    DWORD   Dr1;
    DWORD   Dr2;
    DWORD   Dr3;
    DWORD   Dr6;
    DWORD   Dr7;

    //
    // This section is specified/returned if the
    // ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
    //

    FLOATING_SAVE_AREA FloatSave;

    //
    // This section is specified/returned if the
    // ContextFlags word contians the flag CONTEXT_SEGMENTS.
    //

    DWORD   SegGs;
    DWORD   SegFs;
    DWORD   SegEs;
    DWORD   SegDs;

    //
    // This section is specified/returned if the
    // ContextFlags word contians the flag CONTEXT_INTEGER.
    //

    DWORD   Edi;
    DWORD   Esi;
    DWORD   Ebx;
    DWORD   Edx;
    DWORD   Ecx;
    DWORD   Eax;

    //
    // This section is specified/returned if the
    // ContextFlags word contians the flag CONTEXT_CONTROL.
    //

    DWORD   Ebp;
    DWORD   Eip;
    DWORD   SegCs;              // MUST BE SANITIZED
    DWORD   EFlags;             // MUST BE SANITIZED
    DWORD   Esp;
    DWORD   SegSs;

    //
    // This section is specified/returned if the ContextFlags word
    // contains the flag CONTEXT_EXTENDED_REGISTERS.
    // The format and contexts are processor specific
    //

    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;

BOOL GetThreadContext(
	HANDLE hThread,
	LPCONTEXT lpContext
);

// Create a CONTEXT structure.
CONTEXT Context;

// Tell the system that we are interested in only the
// control registers.
Context.ContextFlags = CONTEXT_CONTROL;

// Tell the system to get the registers associated with a thread.
GetThreadContext( hThread, &Context );

// The control register members in the CONTEXT structure
// reflect the thread's control registers. The other members
// are undefined.

// Tell the system that we are interested
// in the control and integer registers.
Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;

// Tell the system we are interested in the important registers.
Context.ContextFlags = CONTEXT_FULL;

CPU TypeDefinition of CONTEXT_FULL
x86 CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS
Alpha CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER

CPU TypeInstruction PointerStack Pointer
x86 CONTEXT.Eip CONTEXT.Esp
Alpha CONTEXT.Fir CONTEXT.IntSp

BOOL SetThreadContext(
	HANDLE hThread,
	CONST CONTEXT* lpContext
);

CONTEXT Context;

// Stop the thread from running.
SuspendThread( hThread );

// Get the thread's context registers.
Context.ContextFlags = CONTEXT_CONTROL;
GetThreadContext( hThread, &Context );

// Make the instruction pointer point to the address of your choice.
// Here I've arbitrarily set the address instruction pointer to
// 0x00010000.
#if defined(_ALPHA_)
Context.Fir = 0x00010000;
#elif defined(_X86_)
Context.Eip = 0x00010000;
#else
#error Module contains CPU-specific code; modify and recompile.
#endif

// Set the thread's registers to reflect the changed values.
// It's not really necessary to reset the ControlFlags member
// because it was set earlier.
Context.ControlFlags = CONTEXT_CONTROL;
SetThreadContext( hThread, &Context );

// Resuming the thread will cause it to begin execution
// at address 0x00010000.
ResumeThread( hThread );

8 Thread Priorities #



9 An Abstract View of Priorities #


Priority ClassDescription
Real-time The threads in this process must respond immediately to events in order to execute time-critical tasks. Threads in this process also preempt operating system components. Use this priority class with extreme caution.
High The threads in this process must respond immediately to events in order to execute time-critical tasks. The Task Manager runs at this class so a user can kill runaway processes.
Above normal The threads in this process run between the normal and high priority classes (new in Windows 2000).
Normal The threads in this process have no special scheduling needs.
Below normal The threads in this process run between the normal and idle priority classes (new in Windows 2000).
Idle The threads in this process run when the system is otherwise idle. This process is typically used by screensavers or background utility and statistic-gathering software.

Relative Thread PriorityDescription
Time-critical Thread runs at 31 for the real-time priority class and at 15 for all other priority classes.
Highest Thread runs two levels above normal.
Above normal Thread runs one level above normal.
Normal Thread runs normally for the process's priority class.
Below normal Thread runs one level below normal.
Lowest Thread runs two levels below normal.
Idle Thread runs at 16 for the real-time priority class and at 1 for all other priority classes.

Process Priority Class
Relative Thread PriorityIdleBelow NormalNormalAbove NormalHighReal-Time
Time-critical 15 15 15 15 15 31
Highest 6 8 10 12 15 26
Above normal 5 7 9 11 14 25
Normal 4 6 8 10 13 24
Below normal 3 5 7 9 12 23
Lowest 2 4 6 8 11 22
Idle 1 1 1 1 1 16

10 Programming Priorities #


Priority ClassSymbolic Identifiers
Real-time REALTIME_PRIORITY_CLASS
High HIGH_PRIORITY_CLASS
Above normal ABOVE_NORMAL_PRIORITY_CLASS
Normal NORMAL_PRIORITY_CLASS
Below normal BELOW_NORMAL_PRIORITY_CLASS
Idle IDLE_PRIORITY_CLASS

BOOL SetPriorityClass(
	HANDLE hProcess,
	DWORD fdwPriority
);

BOOL SetPriorityClass(
	GetCurrentProcess(),
	IDLE_PRIORITY_CLASS
);

DWORD GetPriorityClass( HANDLE hProcess );

C:\>START /LOW CALC.EXE

BOOL SetThreadPriority(
	HANDLE hThread,
	int nPriority
);

Relative Thread PrioritySymbolic Constant
Time-critical THREAD_PRIORITY_TIME_CRITICAL
Highest THREAD_PRIORITY_HIGHEST
Above normal THREAD_PRIORITY_ABOVE_NORMAL
Normal THREAD_PRIORITY_NORMAL
Below normal THREAD_PRIORITY_BELOW_NORMAL
Lowest THREAD_PRIORITY_LOWEST
Idle THREAD_PRIORITY_IDLE

int GetThreadPriority( HANDLE hThread );

DWORD dwThreadID;
HANDLE hThread = CreateThread( NULL, 0, ThreadFunc, NULL,
    CREATE_SUSPENDED, &dwThreadID );
SetThreadPriority( hThread, THREAD_PRIORITY_IDLE );
ResumeThread( hThread );
CloseHandle( hThread );

10.1 Dynamically Boosting Thread Priority Levels #


BOOL SetProcessPriorityBoost(
	HANDLE hProcess,
	BOOL DisablePriorityBoost
);

BOOL SetThreadPriorityBoost(
	HANDLE hThread,
	BOOL DisablePriorityBoost
);

BOOL GetProcessPriorityBoost(
	HANDLE hProcess,
	PBOOL pDisablePriorityBoost
);

BOOL GetThreadPriorityBoost(
	HANDLE hThread,
	PBOOL pDisablePriorityBoost
);

10.2 Tweaking the Scheduler for the Foreground Process #


10.3 The Scheduling Lab Sample Application #


SchedLab.cpp

/******************************************************************************
Module:  SchedLab.cpp
Notices: Copyright (c) 2000 Jeffrey Richter
******************************************************************************/


#include "..\CmnHdr.H"      /* See Appendix A. */
#include <windowsx.h>
#include <tchar.h>
#include <process.h>        // For _beginthreadex
#include "Resource.H"


///////////////////////////////////////////////////////////////////////////////


DWORD WINAPI ThreadFunc( PVOID pvParam )
{
    HANDLE hThreadPrimary = (HANDLE) pvParam;
    SuspendThread( hThreadPrimary );
    chMB(
        "The Primary thread is suspended.\n"
        "It no longer responds to input and produces no output.\n"
        "Press OK to resume the primary thread & exit this secondary thread.\n"
    );
    ResumeThread( hThreadPrimary );
    CloseHandle( hThreadPrimary );

    // To avoid deadlock, call EnableWindow after ResumeThread.
    EnableWindow(
        GetDlgItem( FindWindow( NULL, TEXT( "Scheduling Lab" ) ), IDC_SUSPEND ),
        TRUE );
    return ( 0 );
}


///////////////////////////////////////////////////////////////////////////////


BOOL Dlg_OnInitDialog( HWND hwnd, HWND hwndFocus, LPARAM lParam )
{
    chSETDLGICONS( hwnd, IDI_SCHEDLAB );

    // Initialize process priority classes
    HWND hwndCtl = GetDlgItem( hwnd, IDC_PROCESSPRIORITYCLASS );

    int n = ComboBox_AddString( hwndCtl, TEXT( "High" ) );
    ComboBox_SetItemData( hwndCtl, n, HIGH_PRIORITY_CLASS );

    // Save our current priority class
    DWORD dwpc = GetPriorityClass( GetCurrentProcess() );

    if( SetPriorityClass( GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS ) )
    {
        // This system supports the BELOW_NORMAL_PRIORITY_CLASS class

        // Restore our original priority class
        SetPriorityClass( GetCurrentProcess(), dwpc );

        // Add the Above Normal priority class
        n = ComboBox_AddString( hwndCtl, TEXT( "Above normal" ) );
        ComboBox_SetItemData( hwndCtl, n, ABOVE_NORMAL_PRIORITY_CLASS );

        dwpc = 0;  // Remember that this system supports below normal
    }

    int nNormal = n = ComboBox_AddString( hwndCtl, TEXT( "Normal" ) );
    ComboBox_SetItemData( hwndCtl, n, NORMAL_PRIORITY_CLASS );

    if( dwpc == 0 )
    {
        // This system supports the BELOW_NORMAL_PRIORITY_CLASS class

        // Add the Below Normal priority class
        n = ComboBox_AddString( hwndCtl, TEXT( "Below normal" ) );
        ComboBox_SetItemData( hwndCtl, n, BELOW_NORMAL_PRIORITY_CLASS );
    }

    n = ComboBox_AddString( hwndCtl, TEXT( "Idle" ) );
    ComboBox_SetItemData( hwndCtl, n, IDLE_PRIORITY_CLASS );

    ComboBox_SetCurSel( hwndCtl, nNormal );

    // Initialize thread relative priorities
    hwndCtl = GetDlgItem( hwnd, IDC_THREADRELATIVEPRIORITY );

    n = ComboBox_AddString( hwndCtl, TEXT( "Time critical" ) );
    ComboBox_SetItemData( hwndCtl, n, THREAD_PRIORITY_TIME_CRITICAL );

    n = ComboBox_AddString( hwndCtl, TEXT( "Highest" ) );
    ComboBox_SetItemData( hwndCtl, n, THREAD_PRIORITY_HIGHEST );

    n = ComboBox_AddString( hwndCtl, TEXT( "Above normal" ) );
    ComboBox_SetItemData( hwndCtl, n, THREAD_PRIORITY_ABOVE_NORMAL );

    nNormal = n = ComboBox_AddString( hwndCtl, TEXT( "Normal" ) );
    ComboBox_SetItemData( hwndCtl, n, THREAD_PRIORITY_NORMAL );

    n = ComboBox_AddString( hwndCtl, TEXT( "Below normal" ) );
    ComboBox_SetItemData( hwndCtl, n, THREAD_PRIORITY_BELOW_NORMAL );

    n = ComboBox_AddString( hwndCtl, TEXT( "Lowest" ) );
    ComboBox_SetItemData( hwndCtl, n, THREAD_PRIORITY_LOWEST );

    n = ComboBox_AddString( hwndCtl, TEXT( "Idle" ) );
    ComboBox_SetItemData( hwndCtl, n, THREAD_PRIORITY_IDLE );

    ComboBox_SetCurSel( hwndCtl, nNormal );

    Edit_LimitText( GetDlgItem( hwnd, IDC_SLEEPTIME ), 4 );     // Maximum of 9999

    return ( TRUE );
}


///////////////////////////////////////////////////////////////////////////////


void Dlg_OnCommand( HWND hwnd, int id, HWND hwndCtl, UINT codeNotify )
{
    switch( id ) {
        case IDCANCEL:
            PostQuitMessage( 0 );
            break;

        case IDC_PROCESSPRIORITYCLASS:
            if( codeNotify == CBN_SELCHANGE )
            {
                SetPriorityClass( GetCurrentProcess(), (DWORD)
                    ComboBox_GetItemData( hwndCtl, ComboBox_GetCurSel( hwndCtl ) ) );
            }
            break;

        case IDC_THREADRELATIVEPRIORITY:
            if( codeNotify == CBN_SELCHANGE )
            {
                SetThreadPriority( GetCurrentThread(), (DWORD)
                    ComboBox_GetItemData( hwndCtl, ComboBox_GetCurSel( hwndCtl ) ) );
            }
            break;

        case IDC_SUSPEND:
            // To avoid deadlock, call EnableWindow before creating
            // the thread which calls SuspendThread.
            EnableWindow( hwndCtl, FALSE );

            HANDLE hThreadPrimary;
            DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
                GetCurrentProcess(), &hThreadPrimary,
                THREAD_SUSPEND_RESUME, FALSE, DUPLICATE_SAME_ACCESS );
            DWORD dwThreadID;
            CloseHandle( chBEGINTHREADEX( NULL, 0, ThreadFunc,
                hThreadPrimary, 0, &dwThreadID ) );
            break;
    }
}


///////////////////////////////////////////////////////////////////////////////


INT_PTR WINAPI Dlg_Proc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    switch( uMsg ) {
        chHANDLE_DLGMSG( hwnd, WM_INITDIALOG, Dlg_OnInitDialog );
        chHANDLE_DLGMSG( hwnd, WM_COMMAND,    Dlg_OnCommand );
    }

    return ( FALSE );
}


///////////////////////////////////////////////////////////////////////////////


int WINAPI _tWinMain( HINSTANCE hinstExe, HINSTANCE, LPTSTR pszCmdLine, int )
{
    HWND hwnd =
        CreateDialog( hinstExe, MAKEINTRESOURCE( IDD_SCHEDLAB ), NULL, Dlg_Proc );
    BOOL fQuit = FALSE;

    while( !fQuit ) {
        MSG msg;
        if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        {
            // IsDialogMessage allows keyboard navigation to work properly.
            if( !IsDialogMessage( hwnd, &msg ) )
            {
                if( msg.message == WM_QUIT )
                {
                    fQuit = TRUE;       // For WM_QUIT, terminate the loop.
                } else {
                    // Not a WM_QUIT message. Translate it and dispatch it.
                    TranslateMessage( &msg );
                    DispatchMessage( &msg );
                }
            }   // if( !IsDialogMessage() )
        } else {

            // Add a number to the listbox
            static int s_n = -1;
            TCHAR sz[20];
            wsprintf( sz, TEXT( "%u" ), ++s_n );
            HWND hwndWork = GetDlgItem( hwnd, IDC_WORK );
            ListBox_SetCurSel( hwndWork, ListBox_AddString( hwndWork, sz ) );

            // Remove some strings if there are too many entries
            while( ListBox_GetCount( hwndWork ) > 100 )
                ListBox_DeleteString( hwndWork, 0 );

            // How long should the thread sleep
            int nSleep = GetDlgItemInt( hwnd, IDC_SLEEPTIME, NULL, FALSE );
            if( chINRANGE( 1, nSleep, 9999 ) )
                Sleep( nSleep );
        }
    }
    DestroyWindow( hwnd );

    return ( 0 );
}


//////////////////////////////// End of File //////////////////////////////////

SchedLab.rc

// Microsoft Developer Studio generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32

/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_SCHEDLAB DIALOGEX 0, 0, 209, 70
STYLE DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION |
    WS_SYSMENU
EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE
CAPTION "Scheduling Lab"
FONT 8, "MS Sans Serif"
BEGIN
    LTEXT           "&Process priority class:",IDC_STATIC,4,6,68,8
    COMBOBOX        IDC_PROCESSPRIORITYCLASS,84,4,72,80,CBS_DROPDOWNLIST |
                    WS_TABSTOP
    LTEXT           "&Thread relative priority:",IDC_STATIC,4,20,72,8
    COMBOBOX        IDC_THREADRELATIVEPRIORITY,84,18,72,76,CBS_DROPDOWNLIST |
                    WS_TABSTOP
    LTEXT           "Sleep (0 to 9999 &ms):",IDC_STATIC,4,36,68,8
    EDITTEXT        IDC_SLEEPTIME,84,34,32,14,ES_NUMBER
    PUSHBUTTON      "&Suspend",IDC_SUSPEND,4,52,49,14
    LISTBOX         IDC_WORK,160,4,48,60,NOT LBS_NOTIFY |
                    LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_TABSTOP
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
    IDD_SCHEDLAB, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 202
        TOPMARGIN, 7
        BOTTOMMARGIN, 63
    END
END
#endif  // APSTUDIO_INVOKED


#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE DISCARDABLE
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE DISCARDABLE
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE DISCARDABLE
BEGIN
    "\r\n"
    "\0"
END

#endif  // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_SCHEDLAB            ICON    DISCARDABLE     "SchedLab.ico"
#endif  // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif  // not APSTUDIO_INVOKED

11 Affinities #


Programming/Thread/NUMA_Machine.gif

BOOL SetProcessAffinityMask(
	HANDLE hProcess,
	DWORD_PTR dwProcessAffinityMask
);

BOOL GetProcessAffinityMask(
	HANDLE hProcess,
	PDWORD_PTR pdwProcessAffinityMask,
	PDWORD_PTR pdwSystemAffinityMask
);

DWORD_PTR SetThreadAffinityMask(
	HANDLE hThread,
	DWORD_PTR dwThreadAffinityMask
);

// Thread 0 can only run on CPU 0.
SetThreadAffinityMask( hThread0, 0x00000001 );

// Threads 1, 2, 3 run on CPUs 1, 2, 3.
SetThreadAffinityMask( hThread1, 0x0000000E );
SetThreadAffinityMask( hThread2, 0x0000000E );
SetThreadAffinityMask( hThread3, 0x0000000E );

ThreadPriorityAffinity MaskResult
A 4 0x00000001 CPU 0
B 8 0x00000003 CPU 1
C 6 0x00000002 Can't run

DWORD SetThreadIdealProcessor(
	HANDLE hThread,
	DWORD dwIdealProcessor
);

// Load the EXE into memory.
PLOADED_IMAGE pLoadedImage = ImageLoad( szExeName, NULL );

// Get the current load configuration information for the EXE.
IMAGE_LOAD_CONFIG_DIRECTORY ilcd;
GetImageConfigInformation( pLoadedImage, &ilcd );

// Change the processor affinity mask.
ilcd.ProcessAffinityMask = 0x00000003;  // I desire CPUs 0 and 1

// Save the new load configuration information.
SetImageConfigInformation( pLoadedImage, &ilcd );

// Unload the EXE from memory.
ImageUnload( pLoadedImage );

usage: IMAGECFG [switches] image-names...
			[-?] display this message
			[-a Process Affinity mask value in hex]
			[-b BuildNumber]
			[-c Win32 GetVersionEx Service Pack return value in hex]
			[-d decommit thresholds]
			[-g bitsToClear bitsToSet]
			[-h 1|0 (Enable/Disable Terminal Server Compatible bit)
			[-k StackReserve[.StackCommit]
			[-l enable large (>2GB) adresses
			[-m maximum allocation size]
			[-n bind no longer allowed on this image
			[-o default critical section timeout
			[-p process heap flags]
			[-q only print config info if changed
			[-r run with restricted working set]
			[-s path to symbol files]
			[-t VirtualAlloc threshold]
			[-u Marks image as uniprocesor only]
			[-v MajorVersion.MinorVersion]
			[-w Win32 GetVersion return value in hex]
			[-x Mark image as Net - Run From Swapfile
			[-y Mark image as Removable - Run From Swapfile

[boot loader]
timeout=2
default=multi(0)disk(0)rdisk(0)partition(1)\WINNT
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows 2000 Server"
	/fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows 2000 Server"
	/fastdetect /NumProcs=1



CategoryTranslation

EditText|FindPage|DeletePage|LikePages| Valid XHTML 1.0! Valid CSS! powered by MoniWiki