c_cpp 스레드개념
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp 스레드개념相关的知识,希望对你有一定的参考价值。
# 스레드 개념
## 세마포어(Semaphore)
세마포어(semaphore)는 에츠허르 다익스트라가 제안한 교착 상태에 대한 해법으로
두개의 Atomic한 함수로 제어되는 정수 변수로 멀티프로그래밍 환경에서 공유자원에
대한 접근 제어를 하는 방식으로 1개의 공유되는 자원에 제한된 개수의 프로세스, 또는
스레드만 접근할 수 있도록 한다. 세마포어의 카운트는 1 이상이며 카운트를 조절하여
진입 가능한 프로세스/스레드 수를 조절할 수 있다. 세마포터 카운트가 항상 1인 것은 아니다.
### 필요한 이유
예를 들어, 아래의 변수가 있다고 하자.
```cpp
int a = 0;
```
이러한 상황에 해당 값은 전역변수로 설정되어있고, 이 프로그램은 여러개의 **쓰레드**가 a의 값을 증가시키는 프로그램이라고 할 때 이러한 증상이 발생한다.
- Process A → fetch a(0)
- Process B → fetch a(0)
- Process A → increase a(1)
- Process A → Store a back(1)
- Process B → increase a(1)
- Process B → Store a back(1)
여기서, 외부에서 보게되면 변수 a에 대해서 1씩 증가하는 과정이 2번 일어났다.
그럼으로 B프로세스가 종료되었을 때는 a는 2가 되어야 하나 여기서는 1이 되어버렸다.
즉, A가 결과를 주기 전에 B가 수행되면서 엉뚱한 값을 시작값으로 가져와서 결과가 잘못 나와 버렸다.
이를 방지하기 위해서 세마포어를 이용하여 a 변수에 Process A가 접근 하고 있을 때 Process B를 정지 시키고
Process A가 종료 되었을 때 B가 시작되도록 다시 시작하게 하면 해결된다.
## 뮤텍스(Mutex)
뮤텍스는 상호 배제(Mutual exclusion)의 약자이다. *쓰레드*들의 실행 시간이 서로 겹치지 않게 해준다.
뮤텍스는 세마포어가 될 수 없지만, 세마포어는 뮤텍스가 될 수 있다.
// sample_multithread_c_program.c
// compile with: /c
//
// Bounce - Creates a new thread each time the letter 'a' is typed.
// Each thread bounces a happy face of a different color around
// the screen. All threads are terminated when the letter 'Q' is
// entered.
//
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>
#define MAX_THREADS 32
// The function getrandom returns a random number between
// min and max, which must be in integer range.
#define getrandom( min, max ) (SHORT)((rand() % (int)(((max) + 1) - (min))) + (min))
int main (void); // Thread 1: main
void KbdFunc(void); // keyboard input, thread dispatch
void BounceProc(void *MyID); // Thread 2 to n: display
void ClearScreen(void); // Screen clear
void ShutDown(void); // Program shutdown
void WriteTitle(int ThreadNum); // Display title bar information
HANDLE hConsoleOut; // Handle to the console
HANDLE hRunMutex; // "Keep Running" mutex
HANDLE hScreenMutex; // "Screen update" mutex
int ThreadNr; // Number of threads started
CONSOLE_SCREEN_BUFFER_INFO csbInfo; // Console infomation
int main() // Thread One
{
// Get display screen information & clear the screen
hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsoleOut, &csbInfo);
ClearScreen();
WriteTitle(0);
// Create the mutexes and reset thread count.
hScreenMutex = CreateMutex(NULL, FALSE, NULL); // Cleared
hRunMutex = CreateMutex(NULL, TRUE, NULL); // Set
ThreadNr = 0;
// Start waiting for keyboard input to dispatch threads or exit
KbdFunc();
// All threads done. Clean up handles.
CloseHandle(hScreenMutex);
CloseHandle(hRunMutex);
CloseHandle(hConsoleOut);
}
void ShutDown(void) // Shut down threads
{
while (ThreadNr > 0)
{
// Tell thread to die and record its death
ReleaseMutex(hRunMutex);
ThreadNr--;
}
// Clean up display when done
WaitForSingleObject(hScreenMutex, INFINITE);
ClearScreen();
}
void KbdFunc(void) // Dispatch and count threads
{
int KeyInfo;
do
{
KeyInfo = _getch();
if (tolower(KeyInfo) == 'a' && ThreadNr < MAX_THREADS)
{
ThreadNr++;
_beginthread(BounceProc, 0, &ThreadNr);
WriteTitle(ThreadNr);
}
} while (tolower(KeyInfo) != 'q');
ShutDown();
}
void BounceProc(void *pMyID)
{
char MyCell, OldCell;
WORD MyAttrib, OldAttrib;
char BlankCell = 0x20;
COORD Coords, Delta;
COORD Old = {0,0};
DWORD Dummy;
char *MyID = (char*)pMyID;
// Generate update increments and initial
// display coordinates.
srand( (unsigned int) *MyID * 3);
Coords.X = getrandom( 0, csbInfo.dwSize.X - 1);
Coords.Y = getrandom( 0, csbInfo.dwSize.Y - 1);
Delta.X = getrandom( -3, 3 );
Delta.Y = getrandom( -3, 3 );
// Set up "happy face" & generate color
// attribute from thread number.
if (*MyID > 16)
MyCell = 0x01; // outline face
else
MyCell = 0x02; // solid face
MyAttrib = *MyID & 0x0F; // force black background
do
{
// Wait for display to be available, then lock it.
WaitForSingleObject(hScreenMutex, INFINITE);
// If we still occupy the old screed position, blank it out.
ReadConsoleOutputCharacter(hConsoleOut, &OldCell, 1, Old, &Dummy);
ReadConsoleOutputCharacter(hConsoleOut, &OldAttrib, 1, Old, &Dummy);
if ((OldCell == MyCell) && (OldAttrib == MyAttrib))
WriteConsoleOutputCharacter(hConsoleOut, &BlankCell, 1, Old, &Dummy);
// Draw new face, then clear screen lock
WriteConsoleOutputCharacter(hConsoleOut, &MyCell, 1, Coords, &Dummy);
WriteConsoleOutputCharacter(hConsoleOut, &MyAttrib, 1, Coords, &Dummy);
ReleaseMutex(hScreenMutex);
// Increment the coordinates for next placement of the black
Old.X = Coords.X;
Old.Y = Coords.Y;
Coords.X += Delta.X;
Coords.Y += Delta.Y;
// If we are about to go off the screen, reverse direction
if (Coords.X < 0 || Coords.X >= csbInfo.dwSize.X)
{
Delta.X = -Delta.X;
Beep(400, 50);
}
if (Coords.Y < 0 || Coords.Y > csbInfo.dwSize.Y)
{
Delta.Y = -Delta.Y;
Beep(600, 50);
}
// Repeat while RunMutex is still taken.
} while (WaitForSingleObject(hRunMutex, 75L) == WAIT_TIMEOUT);
}
void WriteTitle(int ThreadNum)
{
enum {
sizeofNThreadMsg = 80
};
char NThreadMsg[sizeofNThreadMsg];
sprintf_s(NThreadMsg, sizeofNThreadMsg,
"Threads running: %02d. Press 'A ' to start a thread, 'Q' to quit.", ThreadNum);
}
void ClearScreen(void)
{
DWORD dummy;
COORD Home = {0,0};
FillConsoleOutputCharacter( hConsoleOut, ' ',
csbInfo.dwSize.X * csbInfo.dwSize.Y,
Home, &dummy );
}
以上是关于c_cpp 스레드개념的主要内容,如果未能解决你的问题,请参考以下文章