-
WindowsPlatform/프로세스 2009. 2. 10. 21:10작업 객체
CreateJobObject()
OpenJobObject()
AssignProcessToJobObject()
SetInformationJobObject()
QueryJobInformationObject()
커널 오브젝트
Usage Counting
Security
프로세스
커널 오브젝트 핸들 테이블
액세스 마스크
Flags
HANDLE_FLAG_INHERITCreateProcess()
ExitProcess()
TerminateProcess()
WaitForSingleObject()
WaitForInputIdle()
GetExitCodeProcess()
GetProcessHandleCount()
GetCurrentProcess()
GetModuleFileName()
GetModuleFileNameEx()
SetHandleInformation()
GetHandleInformation()
DuplicateHandle()DUPLICATE_SAME_ACCESSGetEnvironmentVariable()
SetEnvironmentVariable()
GetProcessTimes()
SetPriorityClass()
GetPriorityClass()
SetThreadPriorityBoost()
ShellExecute()
GetProcessMemoryInfo()
EnumProcesses()
OpenProcess()
CloseHandle()
EnumProcessModules()
GetModuleFileNameEx()
GetModuleBaseName()
int _tmain (DWORD argc, LPTSTR argv [])
/* Create a separate process to search each file on the
command line. Each process is given a temporary file,
in the current directory, to receive the results. */
{
HANDLE hTempFile;
SECURITY_ATTRIBUTES StdOutSA = /* SA for inheritable handle. */
{sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
TCHAR CommandLine [MAX_PATH + 100];
STARTUPINFO StartUpSearch, StartUp;
PROCESS_INFORMATION ProcessInfo;
DWORD iProc, ExCode;
HANDLE *hProc; /* Pointer to an array of proc handles. */
typedef struct {TCHAR TempFile [MAX_PATH];} PROCFILE;
PROCFILE *ProcFile; /* Pointer to array of temp file names. */
if (argc < 3)
ReportError (_T ("Usage: grepMP pattern files."), 1, FALSE);
/* Startup info for each child search process as well as
the child process that will display the results. */
GetStartupInfo (&StartUpSearch);
GetStartupInfo (&StartUp);
/* Allocate storage for an array of process data structures,
each containing a process handle and a temporary file name. */
ProcFile = malloc ((argc - 2) * sizeof (PROCFILE));
hProc = malloc ((argc-2) * sizeof (HANDLE));
/* Create a separate "grep" process for each file on the
command line. Each process also gets a temporary file
name for the results; the handle is communicated through
the STARTUPINFO structure. argv [1] is the search pattern. */
for (iProc = 0; iProc < argc - 2; iProc++) {
/* Create a command line of the form: grep argv [1] argv [iProc + 2] */
_stprintf (CommandLine, _T ("%s%s %s"),
_T ("grep "), argv [1], argv [iProc + 2]);
/* Create the temp file name for std output. */
if (GetTempFileName (_T ("."), _T ("gtm"), 0,
ProcFile [iProc].TempFile) == 0)
ReportError (_T ("Temp file failure."), 2, TRUE);
/* Set the std output for the search process. */
hTempFile = /* This handle is inheritable */
CreateFile (ProcFile [iProc].TempFile,
/** GENERIC_READ | Read access not required **/ GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, &StdOutSA,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hTempFile == INVALID_HANDLE_VALUE)
ReportError (_T ("Failure opening temp file."), 3, TRUE);
/* Specify that the new process takes its std output
from the temporary file's handles. */
StartUpSearch.dwFlags = STARTF_USESTDHANDLES;
StartUpSearch.hStdOutput = hTempFile;
StartUpSearch.hStdError = hTempFile;
StartUpSearch.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
/* Create a process to execute the command line. */
if (!CreateProcess (NULL, CommandLine, NULL, NULL,
TRUE, 0, NULL, NULL, &StartUpSearch, &ProcessInfo))
ReportError (_T ("ProcCreate failed."), 4, TRUE);
/* Close unwanted handles */
CloseHandle (hTempFile); CloseHandle (ProcessInfo.hThread);
/* Save the process handle. */
hProc [iProc] = ProcessInfo.hProcess;
}
/* Processes are all running. Wait for them to complete, then output
the results - in the order of the command line file names. */
for (iProc = 0; iProc < argc-2; iProc += MAXIMUM_WAIT_OBJECTS)
WaitForMultipleObjects (min(MAXIMUM_WAIT_OBJECTS, argc - 2 - iProc),
&hProc[iProc], TRUE, INFINITE);
/* Result files sent to std output using "cat".
Delete each temporary file upon completion. */
for (iProc = 0; iProc < argc - 2; iProc++) {
if (GetExitCodeProcess (hProc [iProc], &ExCode) && ExCode == 0) {
/* Pattern was detected - List results. */
/* List the file name if there is more than one file to search */
if (argc > 3) _tprintf (_T("%s:\n"), argv[iProc+2]);
fflush (stdout); /* required by multiple processes using stdout */
_stprintf (CommandLine, _T ("%s%s"),
_T ("cat "), ProcFile [iProc].TempFile);
if (!CreateProcess (NULL, CommandLine, NULL, NULL,
TRUE, 0, NULL, NULL, &StartUp, &ProcessInfo))
ReportError (_T ("Failure executing cat."), 0, TRUE);
else {
WaitForSingleObject (ProcessInfo.hProcess, INFINITE);
CloseHandle (ProcessInfo.hProcess);
CloseHandle (ProcessInfo.hThread);
}
}
CloseHandle (hProc [iProc]);
if (!DeleteFile (ProcFile [iProc].TempFile))
ReportError (_T ("Cannot delete temp file."), 6, TRUE);
}
free (ProcFile); free (hProc);
return 0;
}
int _tmain (int argc, LPTSTR argv [])
{
STARTUPINFO StartUp;
PROCESS_INFORMATION ProcInfo;
union { /* Structure required for file time arithmetic. */
LONGLONG li;
FILETIME ft;
} CreateTime, ExitTime, ElapsedTime;
FILETIME KernelTime, UserTime;
SYSTEMTIME ElTiSys, KeTiSys, UsTiSys, StartTimeSys, ExitTimeSys;
LPTSTR targv = SkipArg (GetCommandLine ());
/* On Windows CE, you need to access the argv[] elements directly */
OSVERSIONINFO OSVer;
BOOL IsNT;
HANDLE hProc;
/* Skip past the first blank-space delimited token on the command line
A more general solution would account for tabs and new lines */
if (argc <= 1)
ReportError (_T("Usage: timep command ..."), 1, FALSE);
/* Determine is this is Windows 2000 or NT. */
OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx (&OSVer))
ReportError (_T("Can not get OS Version info. %d"), 2, TRUE);
IsNT = (OSVer.dwPlatformId == VER_PLATFORM_WIN32_NT);
/* No explicit W2000 or CE values defined. This works on W2000, however */
GetStartupInfo (&StartUp);
GetSystemTime (&StartTimeSys);
/* Execute the command line and wait for the process to complete. */
if (!CreateProcess (NULL, targv, NULL, NULL, TRUE,
NORMAL_PRIORITY_CLASS, NULL, NULL, &StartUp, &ProcInfo))
ReportError (_T ("\nError starting process. %d"), 3, TRUE);
/* Assure that we have all REQUIRED access to the process */
if (!DuplicateHandle (GetCurrentProcess(), ProcInfo.hProcess,
GetCurrentProcess(), &hProc, PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
FALSE, 0))
ReportError (_T("Failure duplicating handle. %d"), 4, TRUE);
if (WaitForSingleObject (hProc, INFINITE) != WAIT_OBJECT_0)
ReportError (_T("Failed waiting for process termination. %d"), 5, TRUE);;
GetSystemTime (&ExitTimeSys);
if (IsNT) { /* Windows NT, all versions. Elapsed, Kernel, & User times. */
if (!GetProcessTimes (hProc, &CreateTime.ft,
&ExitTime.ft, &KernelTime, &UserTime))
ReportError (_T("Can not get process times. %d"), 6, TRUE);
ElapsedTime.li = ExitTime.li - CreateTime.li;
FileTimeToSystemTime (&ElapsedTime.ft, &ElTiSys);
FileTimeToSystemTime (&KernelTime, &KeTiSys);
FileTimeToSystemTime (&UserTime, &UsTiSys);
_tprintf (_T ("Real Time: %02d:%02d:%02d:%03d\n"),
ElTiSys.wHour, ElTiSys.wMinute, ElTiSys.wSecond,
ElTiSys.wMilliseconds);
_tprintf (_T ("User Time: %02d:%02d:%02d:%03d\n"),
UsTiSys.wHour, UsTiSys.wMinute, UsTiSys.wSecond,
UsTiSys.wMilliseconds);
_tprintf (_T ("Sys Time: %02d:%02d:%02d:%03d\n"),
KeTiSys.wHour, KeTiSys.wMinute, KeTiSys.wSecond,
KeTiSys.wMilliseconds);
} else {
/* Windows 9x and CE. Elapsed time only. */
SystemTimeToFileTime (&StartTimeSys, &CreateTime.ft);
SystemTimeToFileTime (&ExitTimeSys, &ExitTime.ft);
ElapsedTime.li = ExitTime.li - CreateTime.li;
FileTimeToSystemTime (&ElapsedTime.ft, &ElTiSys);
_tprintf (_T ("Real Time: %02d:%02d:%02d:%03d\n"),
ElTiSys.wHour, ElTiSys.wMinute, ElTiSys.wSecond,
ElTiSys.wMilliseconds);
}
CloseHandle (ProcInfo.hThread); CloseHandle (ProcInfo.hProcess);
CloseHandle (hProc);
return 0;
}
스레드
프로그램의 설계와 구현을 단순화한다.
신뢰성, 가독성, 유지보수성
C 런타임 라이브러리를 쓰는 경우
코드 생성시 멀티스레드 라이브러리를 사용하도록 한다.
프로젝트에 _MT(/MT or /MD) 매크로가 정의된다.
디폴트 라이브러리 대신 LIBCMT.LIB(or MSVCRT.LIB)와 링크한다.
스레드 생성시 다음 함수를 사용한다.
_beginthreadex() // LIBCMT.LIB(MSVCRT.LIB)//_beginthead()
_endthreadex()
//_endthread()
CreateThread()
CREATE_SUSPENDEDCreateRemoteThread()
OpenThread()
ExitThread()
TerminateThread()
CloseHandle()
GetExitCodeThread()
GetCurrentThread()
GetCurrentTheadId()
DuplicateHandle()
//GetThreadId() // ???
GetProcessIdOfThread()
GetThreadIOPendingFlag()
SuspendThread()
ResumeThread()
SetThreadPriority()
GetThreadPriority()
Sleep()
SwitchToThread()
_kbhit() // #include <conio.h>
typedef struct { /* grep thread's data structure. */
int argc;
TCHAR targv [4] [MAX_COMMAND_LINE];
} GREP_THREAD_ARG;
typedef GREP_THREAD_ARG *PGR_ARGS;
static DWORD WINAPI ThGrep (PGR_ARGS pArgs);
VOID _tmain (int argc, LPTSTR argv [])
/* Create a separate THREAD to search each file on the command line.
Report the results as they come in.
Each thread is given a temporary file, in the current
directory, to receive the results.
This program modifies Program 8-1, which used processes. */
{
PGR_ARGS gArg; /* Points to array of thread args. */
HANDLE * tHandle; /* Points to array of thread handles. */
TCHAR CmdLine [MAX_COMMAND_LINE];
BOOL ok;
DWORD ThdIdxP, ThId, ExitCode;
int iThrd, ThdCnt;
STARTUPINFO StartUp;
PROCESS_INFORMATION ProcessInfo;
/* Start up info for each new process. */
GetStartupInfo (&StartUp);
if (argc < 3)
ReportError (_T ("No file names."), 1, TRUE);
/* Create a separate "grep" thread for each file on the command line.
Each thread also gets a temporary file name for the results.
argv [1] is the search pattern. */
tHandle = malloc ((argc - 2) * sizeof (HANDLE));
gArg = malloc ((argc - 2) * sizeof (GREP_THREAD_ARG));
for (iThrd = 0; iThrd < argc - 2; iThrd++) {
/* Set: targv [1] to the pattern
targv [2] to the input file
targv [3] to the output file. */
_tcscpy (gArg [iThrd].targv [1], argv [1]); /* Pattern. */
_tcscpy (gArg [iThrd].targv [2], argv [iThrd + 2]); /* Search file. */
if (GetTempFileName /* Temp file name */
(".", "Gre", 0, gArg [iThrd].targv [3]) == 0)
ReportError (_T ("Temp file failure."), 3, TRUE);
/* Output file. */
gArg [iThrd].argc = 4;
/* Create a thread to execute the command line. */
tHandle [iThrd] = (HANDLE)_beginthreadex (
NULL, 0, ThGrep, &gArg[iThrd], 0, &ThId);
if (tHandle [iThrd] == 0)
ReportError (_T ("ThreadCreate failed."), 4, TRUE);
}
/* Threads are all running. Wait for them to complete
one at a time and put out the results. */
/* Redirect output for "cat" process listing results. */
StartUp.dwFlags = STARTF_USESTDHANDLES;
StartUp.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
StartUp.hStdError = GetStdHandle (STD_ERROR_HANDLE);
ThdCnt = argc - 2;
while (ThdCnt > 0) {
ThdIdxP = WaitForMultipleObjects (ThdCnt, tHandle, FALSE, INFINITE);
iThrd = (int) ThdIdxP - (int) WAIT_OBJECT_0;
if (iThrd < 0 || iThrd >= ThdCnt)
ReportError (_T ("Thread wait error."), 5,TRUE);
GetExitCodeThread (tHandle [iThrd], &ExitCode);
CloseHandle (tHandle [iThrd]);
/* List file contents (if a pattern match was found)
and wait for the next thread to terminate. */
if (ExitCode == 0) {
if (argc > 3) { /* Print file name if more than one. */
_tprintf (_T ("**Search results - file: %s\n"),
gArg [iThrd].targv [2]);
fflush (stdout);
}
_stprintf (CmdLine, _T ("%s%s"), _T ("cat "),
gArg [iThrd].targv [3]);
ok = CreateProcess (NULL, CmdLine, NULL, NULL,
TRUE, 0, NULL, NULL, &StartUp, &ProcessInfo);
if (!ok) ReportError (_T ("Failure executing cat."), 6, TRUE);
WaitForSingleObject (ProcessInfo.hProcess, INFINITE);
CloseHandle (ProcessInfo.hProcess);
CloseHandle (ProcessInfo.hThread);
}
if (!DeleteFile (gArg [iThrd].targv [3]))
ReportError (_T ("Cannot delete temp file."), 7, TRUE);
/* Move the handle of the last thread in the list
to the slot occupied by thread that just completed
and decrement the thread count. Do the same for
the temp file names. */
tHandle [iThrd] = tHandle [ThdCnt - 1];
_tcscpy (gArg [iThrd].targv [3], gArg [ThdCnt - 1].targv [3]);
_tcscpy (gArg [iThrd].targv [2], gArg [ThdCnt - 1].targv [2]);
ThdCnt--;
}
free (tHandle);
free (gArg);
}
/* Definitions of the record structure in the sort file. */
#define DATALEN 56 /* Correct length for presdnts.txt and monarchs.txt. */
#define KEYLEN 8
typedef struct _RECORD {
TCHAR Key [KEYLEN];
TCHAR Data [DATALEN];
} RECORD;
#define RECSIZE sizeof (RECORD)
typedef RECORD * LPRECORD;
typedef struct _THREADARG { /* Thread argument */
DWORD iTh; /* Thread number: 0, 1, 3, ... */
LPRECORD LowRec; /* Low Record */
LPRECORD HighRec; /* High record */
} THREADARG, *PTHREADARG;
static DWORD WINAPI ThSort (PTHREADARG pThArg);
static int KeyCompare (LPCTSTR, LPCTSTR);
static DWORD nRec; /* Total number of records to be sorted. */
static HANDLE * ThreadHandle;
int _tmain (int argc, TCHAR *argv[])
{
/* The file is the first argument. Sorting is done in place. */
/* Sorting is done in memory heaps. */
HANDLE hFile;
LPRECORD pRecords = NULL;
DWORD FsLow, nRead, LowRecNo, nRecTh, NPr, ThId, iTh;
BOOL NoPrint;
int iFF, iNP;
PTHREADARG ThArg;
LPTSTR StringEnd;
iNP = Options (argc, argv, _T ("n"), &NoPrint, NULL);
iFF = iNP + 1;
NPr = _ttoi (argv [iNP]);
if (argc <= iFF)
ReportError (_T ("Usage: sortMT [options] nTh files."), 1, FALSE);
/* Open the file (use the temporary copy). */
hFile = CreateFile (argv[iFF], GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
ReportException (_T ("Failure to open input file."), 2);
/* Get the file size. */
FsLow = GetFileSize (hFile, NULL);
if (FsLow == 0xFFFFFFFF)
ReportException (_T ("Error getting file size."), 3);
nRec = FsLow / RECSIZE; /* Total number of records. */
nRecTh = nRec / NPr; /* Records per thread. */
ThArg = malloc (NPr * sizeof (THREADARG)); /* Array of thread args. */
ThreadHandle = malloc (NPr * sizeof (HANDLE));
/* Allocate a buffer for the complete file, null terminated with some room to spare. */
pRecords = malloc (FsLow + sizeof (TCHAR)); /* Read the entire file. */
if (!ReadFile (hFile, pRecords, FsLow, &nRead, NULL))
ReportException (_T ("Error reading sort file."), 4);
CloseHandle (hFile);
/* Create the sorting threads. */
LowRecNo = 0;
for (iTh = 0; iTh < NPr; iTh++) {
ThArg [iTh].iTh = iTh;
ThArg [iTh].LowRec = pRecords + LowRecNo;
ThArg [iTh].HighRec = pRecords + (LowRecNo + nRecTh);
LowRecNo += nRecTh;
ThreadHandle [iTh] = (HANDLE)_beginthreadex (
NULL, 0, ThSort, &ThArg [iTh], CREATE_SUSPENDED, &ThId);
}
/* Resume all the initially suspened threads. */
for (iTh = 0; iTh < NPr; iTh++)
ResumeThread (ThreadHandle [iTh]);
/* Wait for the sort-merge threads to complete. */
WaitForSingleObject (ThreadHandle [0], INFINITE);
for (iTh = 0; iTh < NPr; iTh++)
CloseHandle (ThreadHandle [iTh]);
/* Print out the entire sorted file. Treat it as one single string. */
StringEnd = (LPTSTR) pRecords + FsLow;
*StringEnd ='\0';
if (!NoPrint) printf ("%s", (LPCTSTR) pRecords);
free (pRecords); free (ThArg); free (ThreadHandle);
return 0;
} /* End of _tmain. */
static VOID MergeArrays (LPRECORD, LPRECORD);
DWORD WINAPI ThSort (PTHREADARG pThArg)
{
DWORD GrpSize = 2, MyNumber, TwoToI = 1;
/* TwoToI = 2**i, where i is the merge step number. */
DWORD_PTR RecsInGrp;
LPRECORD First;
MyNumber = pThArg->iTh;
First = pThArg->LowRec;
RecsInGrp = pThArg->HighRec - First;
/* Number of records in this group. */
/* GrpSize is the number of original groups now
being merged at the merge step. */
/* AdjOffset is the offset from this group number
to the number whose thread we wait for. */
/* Sort this portion of the array. */
qsort (First, RecsInGrp, RECSIZE, KeyCompare);
/* Either exit the thread or wait for the adjoining thread. */
while ((MyNumber % GrpSize) == 0 && RecsInGrp < nRec) {
/* Merge with the adjacent sorted array. */
WaitForSingleObject (ThreadHandle [MyNumber + TwoToI], INFINITE);
MergeArrays (First, First + RecsInGrp);
RecsInGrp *= 2;
GrpSize *= 2;
TwoToI *=2;
}
_endthreadex (0);
return 0; /* Suppress a warning message. */
}
static VOID MergeArrays (LPRECORD p1, LPRECORD p2)
{
DWORD iRec = 0, i1 = 0, i2 = 0;
DWORD_PTR nRecs;
LPRECORD pDest, p1Hold, pDestHold;
nRecs = p2 - p1;
pDest = pDestHold = malloc (2 * nRecs * RECSIZE);
p1Hold = p1;
while (i1 < nRecs && i2 < nRecs) {
if (KeyCompare ((LPCTSTR)p1, (LPCTSTR)p2) <= 0) {
memcpy (pDest, p1, RECSIZE);
i1++; p1++; pDest++;
}
else {
memcpy (pDest, p2, RECSIZE);
i2++; p2++; pDest++;
}
}
if (i1 >= nRecs)
memcpy (pDest, p2, RECSIZE * (nRecs - i2));
else memcpy (pDest, p1, RECSIZE * (nRecs - i1));
memcpy (p1Hold, pDestHold, 2 * nRecs * RECSIZE);
free (pDestHold);
return;
}
int KeyCompare (LPCTSTR pRec1, LPCTSTR pRec2)
{
DWORD i;
TCHAR b1, b2;
LPRECORD p1, p2;
int Result = 0;
p1 = (LPRECORD)pRec1;
p2 = (LPRECORD)pRec2;
for (i = 0; i < KEYLEN && Result == 0; i++) {
b1 = p1->Key [i];
b2 = p2->Key [i];
if (b1 < b2) Result = -1;
if (b1 > b2) Result = +1;
}
return Result;
}
파이버(co-routine?)
스레드 안에서 태스크들을 분리
커널 지원 쓰레딩(kernel-supported threading)을 사용하지 않는 UNIX 응용들을 포팅하는데 도움이 된다.
ConvertThreadToFiber()
ConvertFiberToThread()
CreateFiber()
DeleteFiber()
GetFiberData()
GetCurrentFiber(()
SwitchToFiber()
파이버 로컬 저장소
참조 사이트:
http://www.codeproject.com/KB/threads/killprocess.aspx?display=Print
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=50&MAEULNo=20&no=792413&ref=792413
http://digitalab.paichai.ac.kr/?document_srl=123575
http://kuaaan.tistory.com/50