동기화 - Win32
자원을 공유시 경쟁 상황
교착 상태
회피 방법
모든 스레드들이 동일한 순서로 동기화 오브젝트들을 얻고 그 반대 순서로 해제
WaitForMultipleObjects()
WaitForMultipleObjects()
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;
}
파일 잠금
HeapLock()
HeadpUnlock()
InterlockedIncrement()
CRITICAL_SECTION
InitializeCriticalSectionAndSpinCount()
DeleteCriticalSection()
EnterCriticalSection()
TryCriticalSection()
SetCriticalSectionSpinCount()
LeaveCriticalSection()
volatile DWORD f_ready, f_stop;
/* ready state flag, stop flag */
volatile DWORD sequence; /* Message block sequence number */
volatile DWORD nCons, nLost;
time_t timestamp;
CRITICAL_SECTION mguard; /* Guard the message block structure */
DWORD checksum; /* Message contents checksum */
DWORD data[DATA_SIZE]; /* Message Contents */
} MSG_BLOCK;
MSG_BLOCK mblock = { 0, 0, 0, 0, 0 };
DWORD WINAPI produce (void *arg)
{
while (!mblock.f_stop) {
/* Get the buffer, fill it */
EnterCriticalSection (&mblock.mguard);
__try {
if (!mblock.f_stop) {
mblock.f_ready = 0;
MessageFill (&mblock);
mblock.f_ready = 1;
mblock.sequence++;
}
}
__finally { LeaveCriticalSection (&mblock.mguard); }
}
return 0;
}
DWORD WINAPI consume (void *arg)
{
DWORD ShutDown = 0;
CHAR command, extra;
/* Consume the NEXT message when prompted by the user */
while (!ShutDown) { /* This is the only thread accessing stdin, stdout */
_tprintf (_T("\n**Enter 'c' for consume; 's' to stop: "));
_tscanf ("%c%c", &command, &extra);
if (command == 's') {
EnterCriticalSection (&mblock.mguard);
ShutDown = mblock.f_stop = 1;
LeaveCriticalSection (&mblock.mguard);
} else if (command == 'c') { /* Get a new buffer to consume */
EnterCriticalSection (&mblock.mguard);
__try {
if (mblock.f_ready == 0)
_tprintf (_T("No new messages. Try again later\n"));
else {
MessageDisplay (&mblock);
mblock.nCons++;
mblock.nLost = mblock.sequence - mblock.nCons;
mblock.f_ready = 0; /* No new messages are ready */
}
}
__finally
{ LeaveCriticalSection (&mblock.mguard); }
} else {
_tprintf (_T("Illegal command. Try again.\n"));
}
}
return 0;
}
{
DWORD Status, ThId;
HANDLE produce_h, consume_h;
InitializeCriticalSection (&mblock.mguard);
/* Create the two threads */
produce_h = (HANDLE)_beginthreadex (NULL, 0, produce, NULL, 0, &ThId);
if (produce_h == NULL)
ReportError (_T("Cannot create producer thread"), 1, TRUE);
consume_h = (HANDLE)_beginthreadex (NULL, 0, consume, NULL, 0, &ThId);
if (consume_h == NULL)
ReportError (_T("Cannot create consumer thread"), 2, TRUE);
/* Wait for the producer and consumer to complete */
Status = WaitForSingleObject (consume_h, INFINITE);
if (Status != WAIT_OBJECT_0)
ReportError (_T("Failed waiting for consumer thread"), 3, TRUE);
Status = WaitForSingleObject (produce_h, INFINITE);
if (Status != WAIT_OBJECT_0)
ReportError (__T("Failed waiting for producer thread"), 4, TRUE);
DeleteCriticalSection (&mblock.mguard);
return 0;
}
뮤텍스
CloseHandle()
세마포어
OpenSemaphorer()
CloseHandle()
//
// Allocated for each client connection
//
typedef struct _CONNECTION_OBJ
{
SOCKET s; // Client socket
HANDLE hRecvSema; // Semaphore incremented for each receive
struct _BUFFER_OBJ *PendingSendHead, // List of pending buffers to send
*PendingSendTail; // End of the list
CRITICAL_SECTION SendRecvQueueCritSec; // Protect access to this structure
} CONNECTION_OBJ;
//
// Function: ReceiveThead
//
// Description:
// One of these threads is started for each client connection.
// This thread sits in a loop, receiving data. For each receive, the
// buffer is queued for sending by the SenderThread for this connection.
//
DWORD WINAPI ReceiveThread(LPVOID lpParam)
{
CONNECTION_OBJ *ConnObj=NULL;
BUFFER_OBJ *BuffObj=NULL;
int rc;
// Retrieve the connection object for this connection
ConnObj = (CONNECTION_OBJ *)lpParam;
if (gProtocol == IPPROTO_UDP)
{
// For UDP all we do is receive packets on the port
while (1)
{
// Allocate the buffer for datagram send/recv
BuffObj = GetBufferObj(gBufferSize);
rc = recvfrom(
ConnObj->s,
BuffObj->buf,
BuffObj->buflen,
0,
(SOCKADDR *)&BuffObj->addr,
&BuffObj->addrlen);
BuffObj->buflen = rc;
/*
if (rc > 0)
{
}
*/
// Queue the receive buffer for sending and signal the send thread
EnqueueBufferObj(ConnObj, BuffObj);
ReleaseSemaphore(ConnObj->hRecvSema, 1, NULL);
if (rc == 0)
{
break;
}
}
}
else if (gProtocol == IPPROTO_TCP)
{
// loop until the connection is closed or is aborted/terminated
while (1)
{
// Allocate the buffer for stream send/recv
BuffObj = GetBufferObj(gBufferSize);
rc = recv(
ConnObj->s,
BuffObj->buf,
BuffObj->buflen,
0);
BuffObj->buflen = rc;
// Queue the receive buffer for sending and signal the send thread
EnqueueBufferObj(ConnObj, BuffObj);
ReleaseSemaphore(ConnObj->hRecvSema, 1, NULL);
if (rc == 0 || rc == SOCKET_ERROR)
{
break;
}
/*
else if (rc != SOCKET_ERROR)
{
}
*/
}
}
ExitThread(0);
return 0;
}
//
// Function: SendThread
//
// Description:
// This is the send thread started for each client connection.
// This thread waits for the semaphore to be signaled indicating that
// the receive thread has queued a buffer for sending.
//
DWORD WINAPI SendThread(LPVOID lpParam)
{
CONNECTION_OBJ *ConnObj=NULL;
BUFFER_OBJ *BuffObj=NULL;
int rc,
nleft,
idx;
// Retrieve the connection object
ConnObj = (CONNECTION_OBJ *)lpParam;
while (1)
{
// Wait for the receive thread to signal us
rc = WaitForSingleObject(ConnObj->hRecvSema, INFINITE);
if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)
{
fprintf(stderr, "WaitForSingleObject failed: %d\n", GetLastError());
ExitProcess(-1);
}
// Retrieve the first buffer from this connection's queue
BuffObj = DequeueBufferObj(ConnObj);
//
// If the this receive by the receive thread indicated zero bytes then
// the connection has been gracefully closed. Otherwise, if an error
// was indicated then the connection was aborted.
//
if ((gProtocol == IPPROTO_TCP ) && ((BuffObj->buflen == 0) || (BuffObj->buflen == SOCKET_ERROR)))
{
FreeBufferObj(BuffObj);
BuffObj = NULL;
break;
}
if (gProtocol == IPPROTO_UDP)
{
// For UDP we send the packet back to the source address
rc = sendto(
ConnObj->s,
BuffObj->buf,
BuffObj->buflen,
0,
(SOCKADDR *)&BuffObj->addr,
BuffObj->addrlen
);
if (BuffObj->buflen == 0)
{
FreeBufferObj(BuffObj);
BuffObj = NULL;
break;
}
}
else if (gProtocol == IPPROTO_TCP)
{
// Otherwise send the buffer on the connection socket
nleft = BuffObj->buflen;
idx = 0;
while (nleft > 0)
{
rc = send(
ConnObj->s,
&BuffObj->buf[idx],
nleft,
0
);
if (rc == SOCKET_ERROR)
{
break;
}
else
{
nleft -= rc;
idx += rc;
}
}
}
if (rc == SOCKET_ERROR)
{
printf("SendThread: send(to) failed: %d\n", WSAGetLastError());
break;
}
/*
else if (rc > 0)
{
}
*/
FreeBufferObj(BuffObj);
BuffObj = NULL;
}
// Close the connection's socket
closesocket(ConnObj->s);
FreeConnectionObj(ConnObj);
ExitThread(0);
return 0;
}
CloseHandle()
SetEvent()
CreateWatableTimer()
CloseHandle()
SetWatableTimer()
CancelWatableTimer()
익명 파이프
지명 파이프
참조 사이트:
http://www.nicklib.com/bbs/board.php?bo_table=bbs_lecture&wr_id=52&page=2