반응형
728x90
반응형

오늘은 C++에서의 쓰레드이다

지겹게 기억을 더듬어가면서 C기반의 포스팅을 했던 적이 있는데 C++에서도 지원을 한다니 새로웠다.

 

C기반 I/O Multithreading - 12. 멀티 프로세싱? 멀티 쓰레딩?

멀티 프로세싱에 이어서, 멀티 프로세싱의 단점이 보완되는 멀티 쓰레딩 개념이다. 사실 단점이 보완되기는 하는데 함께 딸려오는 문제 거리도 만만치 않기 때문에 좀 상세히 볼 필요가 있다ㅋ

typingdog.tistory.com

위 링크는 쓰레드

C++ 에서의 쓰레드

원래 쓰레드의 생성과 사용은 OS에 종속적이었고, API가 C 기반이었다. 하지만 C++ 11 표준에 쓰레드 라이브러리가 따로 들어가면서 OS에 독립적이고, 프로그래밍 언어 차원에서 지원이 된다.

임계 영역과 관련된 문제는 Mutex를 통해서 상호배제를 처리할 것인데 이 또한 C++ 프로그래밍 언어 차원에서 지원이 된다는 것이다. 그래서 C 기반의 코드를 그대로 C++ 코드로 변경하도록 해보겠다. 

일단 간단하게 쓰레드 사용과 그에 동반하는 문제까지 설명하자면,

공용 데이터 영역의 변수(전역 변수)

쓰레드에서 공통으로 접근할 수 있는 데이터 영역의 변수를 두 쓰레드에서 임계영역에서 사용이 되면서 기대하는 값과 다른 결과가 나오는 것에서부터 문제가 된다.

쓰레드 A와 쓰레드 B에 해당하며 동일한 횟수만큼(백만) 증감

쓰레드 A에서는 동일한 횟수만큼 (1,000,000) 공용 Data 영역 변수를 1씩 증가시키고, 쓰레드 B에서는 동일한 횟수만큼 (1,000,000) 공용 Data 영역 변수를 1씩 감소시킨다.

기대하는 값은 0 이겠지만(동일한 횟수만큼 1씩 증가시키고, 감소시켰기 때문) 쓰레드 동기화가 이루어지지 않은 탓에 0이 아닌 다른 값이 나온다.

문제에 대한 자세한 설명은 아래의 링크를 통해서 확인하면 된다.

 

C기반 I/O Multithreading - 14. 쓰레드의 치명적인 문제점

C기반 I/O MultiThreading - 12. 멀티 프로세싱? 멀티 쓰레딩? 멀티 프로세싱에 이어서, 멀티 프로세싱의 단점이 보완되는 멀티 쓰레딩 개념이다. 사실 단점이 보완되기는 하는데 함께 딸려오는 문제 거

typingdog.tistory.com

C언어 기반 쓰레드 구현(Mutex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
 
pthread_mutex_t mutex;
int common_value = 0;
 
void* t_main_plus(void *arg);
void* t_main_minus(void *arg);
 
int main(void)
{
    pthread_t tid1, tid2;
 
    pthread_mutex_init(&mutex, NULL);
 
    pthread_create(&tid1, NULL, t_main_plus, NULL); // 쓰레드 생성
    pthread_create(&tid2, NULL, t_main_minus, NULL); // 쓰레드 생성
 
    pthread_detach(tid1); // tid1 에 해당하는 쓰레드가 종료됨과 동시에 소멸.
    pthread_detach(tid2); // tid2 에 해당하는 쓰레드가 종료됨과 동시에 소멸.
 
    sleep(7); // 종료되지 않도록 대기.
    pthread_mutex_destroy(&mutex);
    printf("메인함수가 종료됩니다. [common_value의 최종 값 : %d]\n",common_value);
    return 0;
}
 
void* t_main_plus(void *arg)
{
    int i = 0;
 
    printf("t_main_plus 쓰레드가 연산을 시작합니다. \n");
 
    pthread_mutex_lock(&mutex);
    for(i=0; i<1000000; i++// for을 중복해서 쓴 것은 100번 type을 검사하는 것보단 났다고 생각.
        common_value+=1;
    pthread_mutex_unlock(&mutex);
 
    printf("t_main_plus 쓰레드가 종료됩니다.\n");
    return NULL;
}
 
 
void* t_main_minus(void *arg)
{
    int i = 0;
 
    printf("t_main_minus 쓰레드가 연산을 시작합니다. \n");
 
    pthread_mutex_lock(&mutex);
    for(i=0; i<1000000; i++// for을 중복해서 쓴 것은 100번 type을 검사하는 것보단 났다고 생각.
        common_value-=1;
    pthread_mutex_unlock(&mutex);
 
    printf("t_main_minus 쓰레드가 종료됩니다.\n");
    return NULL;
}
cs

C++언어 기반 쓰레드 구현(Mutex)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <thread>
#include <mutex>
 
std::mutex mtx;
int comm_value = 0;
 
int main(void)
{
    std::thread t1([]() { mtx.lock(); for (int i = 0; i < 1000000; i++)    comm_value--; mtx.unlock(); });
    std::thread t2([]() { mtx.lock();  for (int i = 0; i < 1000000; i++)    comm_value++; mtx.unlock(); });
 
    t1.join();
    t2.join();
 
    std::cout << "comm_value의 값은 : " << comm_value << std::endl;
    return 0;
}
cs

 

위의 코드가 아래의 코드로 변환되었다고 생각하면 된다. 너무 간단하게 몇 줄이면 끝났다ㅋㅋㅋㅋ

끝.

728x90
반응형
728x90
반응형

 

우선 순위 큐란?

Heap 자료 구조를 내부적으로 사용한다.
기본적으로 값이 클수록(문자의 경우 사전 상 뒤의 순서일수록) 우선순위가 높다. <- 이는 우선 순위를 정하기 나름이다.

이렇게 나올줄 알고 이미 c언어로 구현을 해보았다ㅋ 매우

https://typingdog.tistory.com/110

 

C Data Structure - Heap ( Priority Queue, 우선 순위 큐 ) 개념 및 코드 구현

공부를 하고 정리하는 것이 매우 중요하다. 근데 그 정리를 하기가 조금 귀찮은 것이 아니다. 앞으로는 그 때 그 때 정리하도록 하고, 모아두지 말아야겠다.. 업로드 할 것이 한 두 가지가 아니다

typingdog.tistory.com

 

코드 및 실행 결과

----

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <queue>
#include <iostream>
#include <string>
 
using namespace std;
 
int main(void)
{
    priority_queue<string> pq;
    string words[3= {
        "Apple",
        "Banana",
        "Corn"
    };
    for (int i = 0; i < 3; i++)
        pq.push(words[i]);
    while (!pq.empty())
    {
        cout << pq.top() << endl;
        pq.pop(); // 분명히 top 에서 Pop 으로 뽑아내지만 선입 선출의 순서가 아닌 우선 순위대로 값을 뽑아낸다. 
        // 내부적으로 사용되는 자료 구조 방식이 다르기 때문에.
    }
 
    return 0;
}
cs

----

 

728x90
반응형

'프로그래밍응용 > Modern & STL' 카테고리의 다른 글

자료형 추론 auto / 범위 기반 for  (0) 2021.01.21
Iterator 사용 방법 예시  (0) 2021.01.05
Queue  (0) 2021.01.04
Stack  (0) 2021.01.03
Tuple  (0) 2021.01.03
728x90
반응형

큐란?

컨테이너를 확장 및 축소하여 기능을 제한하거나 특정 기능과 특징을 사용하도록 만든 것을 컨테이너 어댑터라고 하는데, 큐 또한 바로 그것이다. 

내부적으로 dequeue, list 등의 컨테이너로 동작하며 기본적으로는 dequeue로 동작한다. vector는 안된다! 왜냐하면 vector는 앞에서 값을 빼는 pop 기능이 없기 때문이다.( vector::push_back( )과 vector::pop_back( )만 존재함 )

사용되고 있는 내부 컨테이너를 변경하려면 queue<data type, list<int>> listack; 이러한 식으로 진행하면 된다. ( 스택에서 사용될 data type, 변경할 컨테이너 구조: list or dequeue등)

코드 및 실행 결과

----

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <queue>
#include <iostream>
#include <string>
 
using namespace std;
 
int main(void)
{
    queue<string> qu;
    string words[3= {
        "Apple",
        "Banana",
        "Corn"
    };
 
    for (int i = 0; i < 3; i++)
        qu.push(words[i]);
 
    while (!qu.empty())
    {
        cout << qu.front() << endl;
        qu.pop();
    }
    return 0;
}
cs

----

728x90
반응형

'프로그래밍응용 > Modern & STL' 카테고리의 다른 글

Iterator 사용 방법 예시  (0) 2021.01.05
Priority Queue  (0) 2021.01.04
Stack  (0) 2021.01.03
Tuple  (0) 2021.01.03
Pair  (0) 2021.01.03
728x90
반응형

오늘은 컨테이너, 이터레이터, 알고리즘이란 무엇이며, 무엇이 있는지 학습한 결과를 기록한다.

Container

컨테이너는 뜻 그대로 그릇, 무언가 담을 수 있는 역할을 한다. 즉, 자료 및 값을 저장하는 역할을 한다. 이 그릇의 모양이나 크기에 따라 담기를 권장되는 내용물이 다르고 취급 방법이 다르다.(컵이라는 그릇에 라면을 담을 수는 있지만 효율적이지 못한 것처럼.)

먼저, 컨테이너에는 순차 컨테이너, 연관 컨테이너, 컨테이너 어댑터 등이 있다. 

이게 무슨 소리인가? 

순차 컨테이너 : 뭔가 자료들이 순차적으로 들어가는거..?
연관 컨테이너 : 연관되어서 들어가는거..? 쌍으로 연관되어서 들어가는 것인가?
컨테이너 어댑터 : 어댑터란 다른 전기나 기계 장치를 서로 연결해서 작동할 수 있도록 만들어 주는 결합 도구 라는 정의가 있는 것으로 보아, 컨테이너와 컨테이너를 변환할 수 있는 그런게 아닐까?

나는 리얼로 위와 같이 생각했다. 내가 조사해 본 컨테이너들은 다음과 같다.

순차 컨테이너 

말 그대로 순차적으로 자료를 저장한다. 내 예측이 맞았다! 순차 컨테이너에서는 자료의 추가가 빠르지만 탐색할 때에는 시간이 많이 걸린다. 왜냐하면 순차적으로 접근하기 때문에!

이러한 순차 컨테이너에는 vector, deque, list 가 있다. 그렇게 벡터, 벡터했던게 바로 여기서 나오는 개념이었구나~

1. Vector : 동적 배열 처럼 동작하며, 자료는 뒤 쪽에서 추가된다.
2. Deque : 벡터와 유사하지만 앞에서도 자료들이 추가될 수 있다.
3. List : 벡터와 유사하지만 중간에서 자료를 추가하는 연산이 효율적이다.

연관 컨테이너

다음은 연관 컨테이너이다. 연관 컨테이너는 조사해 본 결과 사전과 같은 구조로 자료를 저장한다고 한다. 즉, 키와 값의 형태로 데이터가 저장되고, 자료들은 정렬되어 있으며 이러한 정렬 때문에 자료 추가에는 시간이 걸리지만 탐색은 키를 통하여 한 번에 뽑아내니 빠르다. 

이러한 연관 컨테이너에는 Set, Map, MultiSet, MultiMap 등이 있다

1. set : 집합이라고 하며, 중복이 없는 자료들이 정렬되어 저장된다.
2. map : 맵이라고 하며, key - value 형태로 저장된다.
3. multiset : 다중 집합이라고 하며, 집합과 유사하지만 자료의 중복을 허용한다.
4. multimap : 다중 맵이라고 하며, 맵과 유사하지만 키가 중복될 수 있다.

컨테이너 어댑터

드디어 컨테이너 어댑터이다!

컨테이너 어댑터는 기존 컨테이너의 인터페이시를 제한하여 만든 기능이 제한되거나 변형된 컨테이너를 의미한다고 한다. 이게 무슨 말일까 싶어서 좀 더 확인해보았는데

컨테이너 어댑터에는 Stack이 있다. 이를 예로 들자면, 기본 컨테이너인 벡터는 vector 클래스를 사용하는데 이 클래스의 인터페이스를 제한하고(벡터의 여러 기능들을 제한하고) 특정 형태(스택에 관련된 연산)의 동작 만을 수행하도록 한다.

그러니까 한 마디로 내가 어떤 자료구조를 구현할 것 인데 그냥 밑 바닥부터 구현하기 힘들고 귀찮은데 마침 기가 막히고 검증된 기존의 컨테이너가 있으니 이를 활용하여 확장 및 축소 등의 적용(Adapt)을 하는 것이라고 보면 될 것 같다. 그런데 뭔가 계속 제한한다고 하는데 이는 기존의 컨테이너에서 필요없는 부분은 사용하지 못하도록 하는 의미의 제한인 것 같다.

아무튼, 이러한 컨테이너 어댑터에는 Stack, Queue, Priority queue이 제공된다.

Iterator

이제는 반복자(Iterator)의 개념이다.

이 반복자는 각 컨테이너의 자료구조에 맞는 액세스를 할 수 있도록 도와준다. 예를 들어 순회를 한다거나, 원하는 값이 있는 메모리에 접근 가능하도록. 검증되었기 때문에 안심하고 사용해도 된다.

일종의 포인터와 비슷한 객체이다. 기존의 자료구조에서 보면 링크드 리스트에서만 보더라도 노드를 순회하기 위해서는 포인터의 값을 증가 혹은 감소시키고 여러 검사를 하는 등 작업을 했는데 반복자가 이를 대신해준다고 보면 된다. 

알고리즘마다 각기 다른 방식으로 컨테이너 요소들에 접근하기 때문에 반복자에도 여러 종류들이 존재한다. 그렇기 때문에 컨테이너를 사용한다면 꼭 반복자를 사용해야 한다.

반복자에는 몇 가지 예를 들자면 input iterator, output iterator, forward iterator, bidirectional iterator, random access iterator 등이 있다.

Algorithm

알고리즘은 문제 해결하기 위해서 그 절차나 방법의 공식화를 의미한다.

탐색, 정렬, 반전, 삭제, 변환 등이 있다.

 

위와 같이 3가지 요소로 구성된 것이 C++ STL이라는 것을 학습했고, 대충 개념을 잡게 되었다.

728x90
반응형

'프로그래밍응용 > Modern & STL' 카테고리의 다른 글

Deque  (0) 2020.09.13
모든 컨테이너 공통 멤버  (0) 2020.09.13
Iterator( With vector )  (0) 2020.09.13
Vector  (0) 2020.09.12
C++ STL(Standard Template Library이란?  (0) 2020.09.07
728x90
반응형

Mallocfree의 대체 – newdelete

  • C언어에서의 동적 할당

C언어에서 동적 할당의 단점은 할당 크기를 바이트 단위로 직접 명시해주어야 하고, 반환되는 void *에 대해서 적절한 타입 변환이 이루어지고 대입이 이루어져야 한다.

C++에서의 newdelete 연산자를 사용하면 위의 단점을 모두 커버할 수 있다.



  • C++에서의 동적 할당

다음과 같은 형식으로 동적 할당을 행한다.

그리고 다음은 C 스타일의 동적 할당과 C++ 스타일의 동적 할당을 비교한 것인데 완전히 같은 내용이다.

  • C++의 클래스의 객체 생성 시 new & delete

객체 생성을 할 때에는 꼭 new 연산자를 이용하여 동적 할당하고, delete 연산자를 이용하여 할당을 해체해야 한다. -> Cmalloc & free 함수로 동적 할당 및 해체를 진행할 경우 생성자 / 소멸자의 호출이 이루어지지 않음.

  • 참조자를 통한 힙 영역 참조

참조자를 이용하여 포인터 연산 없이 접근해볼 수 있다.



728x90
반응형

'컴퓨터 언어 정리 > C++ 언어' 카테고리의 다른 글

10 클래스와 객체  (0) 2020.09.11
09 C언어의 표준 함수 호출  (0) 2020.09.10
07 참조자(Reference)  (0) 2020.09.08
06 이름 공간(namespace)  (0) 2020.09.08
05 인라인 함수(inline function)  (0) 2020.09.07
728x90
반응형

함수 오버로딩(Function Overloading)

  • 함수 오버로딩

C 언어에서는 두 함수를 정의하고 선언하는데 함수의 이름이 같으면 아무리 함수의 내용이 다르다고 하더라도 허용하지 않았다. 위의 예제에서 sum을 호출할 때, 어떤 함수의 정의를 타겟으로 호출했는지 알 수 있다. 이렇게 호출되는 함수 명은 같지만 어떤 함수 정의를 타겟으로 하였는지 알 수 있었던 이유는 함수 호출의 인자와 함수 선언의 매개 변수 정보를 통해서 호출하고자 하는 함수를 구분할 수 있다.

, 함수 호출 시 전달되는 인자를 통해 호출되고자 하는 함수의 구분이 가능하기 때문에 C++에서는 함수의 정의에서 매개 변수의 선언 형태가 다르다면 동일한 이름의 함수 정의를 허용할 수 있다.
이를 함수 오버로딩이라 한다.

함수 오버로딩 시 필요한 정보 : 함수 이름 + 함수의 매개변수 + const 여부

함수의 이름은 같아야 함수 오버로딩이 적용되고, 함수의 매개변수의 경우 매개 변수들의 타입 혹은 개수 정보가 달라야 오버로딩이 가능하다. 그리고 const 여부의 경우는 추후 내용 기록한다. 중요한 것은 반환 타입은 오버로딩에 필요한 정보가 아니므로 반환 타입이 다르다고 해서 오버로딩이 적용되지 않는다.





728x90
반응형

'컴퓨터 언어 정리 > C++ 언어' 카테고리의 다른 글

06 이름 공간(namespace)  (0) 2020.09.08
05 인라인 함수(inline function)  (0) 2020.09.07
04 디폴트 매개변수(Default Parameter)  (0) 2020.09.07
02 Bool 자료형  (0) 2020.09.06
01 C++언어의 첫 기본 예제  (0) 2020.09.06
728x90
반응형

Bool 자료형

  • Bool 자료형

개정 C언어와 C++에서는 참과 거짓의 표현을 위한 키워드 truefalse를 정의 하고 있다. 이러한 truefalse 는 단순 10의 값이 아니라, 그 자체로 의미 있는 데이터이기 때문에 이런 유형의 데이터를 저장하기 위한 자료형이 존재한다. truefalse 데이터는 bool형 데이터라고 하고, 이러한 bool형 데이터를 지원하는 기본 자료형 bool이 존재한다.

다음은 bool 자료형을 이용한 예제를 나타낸 소스이다.

사용자로부터 입력 받는 number 변수에 10이 들어가면 true 값을, 그 외의 값이 들어가면 false 값을 반환 한다.

728x90
반응형

+ Recent posts