인프런 커뮤니티 질문&답변

essenger M님의 프로필 이미지
essenger M

작성한 질문수

[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버

연습 문제

연습문제 lock을 써서 해봤는데 결과가 안나오는데 한번 봐주시면 감사하겠습니다.

작성

·

286

1

저는 core개수를 미리 파악하는것은 생각못하고 그냥 쓰레드를 20개 만들어서 20개의 쓰레드들이 5만번씩 소수를 구하는 식으로 하려고 했었는데 prime배열과 최종답인 p_cnt는 쓰레드들이 공유하므로 atomic으로 설정해주었고 이 데이터들에 대해 spinlock을 써서 접근하도록 하였습니다. 

전체 코드는 

//소수 구하기

class SpinLock {

public:

void lock() {

bool expected = false;

bool desired = true;

while (!_locked.compare_exchange_strong(expected, desired)) {

expected = false;

}

}

void unlock() {

_locked.store(false);

}

private:

atomic<bool> _locked = false;

};

SpinLock spinLock;

atomic<int32> p_cnt = 0;

atomic<int32> Prime[1000001];

const int32 MAX_NUMBER = 1000'000;

void GetPrime(int first) {

int n = first + 50000;

for (int i = first; i*i < n; i++) {

for (int j = i * i; j < n; j += i) {

{

lock_guard<SpinLock> lock(spinLock);

if (Prime[j] == 1) continue;

Prime[j] = 1;

}

}

}

for (int i = first; i < first + 50000; i++) {

if (i <= 1) continue;

{

lock_guard<SpinLock> lock(spinLock);

if (Prime[i] == 0) {

p_cnt++;

}

}

}

}

int main()

{

vector<thread> v;

int start = 0;

for (int i = 0; i < 20; i++) {

v.push_back(thread(GetPrime, start));

start += 50000;

}

for (int i = 0; i < 20; i++) {

v[i].join();

}

cout << p_cnt;//소수의 개수

return 0;

}

입니당

답변 5

1

essenger M님의 프로필 이미지
essenger M
질문자

수준 낮은 질문에도 항상 답해주셔서 정말 감사합니다 ㅠㅠ 너무 좋은 강의네요 진짜

1

Rookiss님의 프로필 이미지
Rookiss
지식공유자

lock_guard<SpinLock> lock(spinLock);
cnt++;


이 부분에서 cnt가 애당초 atomic이기 때문에
굳이 위와 같이 락을 잡을 이유가 없습니다.
그리고 경합이 많아질 수록 당연히 성능도 떨어질 수밖에 없습니다.
각자 count 계산을 다 하고, 최종 결과만을 cnt에다 더해주면
경합없이 동작시킬 수 있는데 굳이 1을 더할 때마다 경합을 할 필욘 없겠죠.

0

essenger M님의 프로필 이미지
essenger M
질문자

class SpinLock {

public:

void lock() {

bool expected = false;

bool desired = true;

while (!_locked.compare_exchange_strong(expected, desired)) {

expected = false;

}

}

void unlock() {

_locked.store(false);

}

private:

atomic<bool> _locked = false;

};

SpinLock spinLock;

atomic<int> cnt = 0;

bool IsPrime(int n) {

for (int i = 2; i <= n; i++) {

if (n % i == 0) return false;

}

return true;

}

void PrimeCnt(int first, int last) {

for (int i = first; i < last; i++) {

if (i < 2) continue;

if (IsPrime(i)) {

lock_guard<SpinLock> lock(spinLock);

cnt++;

}

}

}

int main()

{

int result = 0;

vector<thread> v;

int first = 0;

int last = 50000;

for (int i = 0; i < 20; i++) {

//cout << first << ' ' << last << '\n';

v.push_back(thread(PrimeCnt, first, last));

first += 50000;

last += 50000;

}

for (int i = 0; i < 20; i++) {

v[i].join();

}

cout << cnt;

return 0;

}

이런식으로 백만을 구간을 20개로 쪼개서 쓰레드 20개를 생성해서 각 쓰레드가 주어진 구간을 계산하는데

이때 계산하는 방식을 전역변수에 lock을 쥐고 접근하는식으로 하니깐 시간이 너무 오래걸려 나오질 않네요 

저는 동시에 20개의 쓰레드가 한 쓰레드당 5만번의 연산만 하면 되니까 될줄 알았는데 안되네용 애초에

이 문제는 소수의 개수를 전역으로 선언해서 쓰레드들끼리 lock으로 접근하게 하면 안되는 문제인가요..?

0

essenger M님의 프로필 이미지
essenger M
질문자

아.. 맞네요 2부터 시작하는 소수구하는 알고리즘을 그냥 넣었네요 다른방식으로 해보고 또 질문드리겠습니다..!

0

Rookiss님의 프로필 이미지
Rookiss
지식공유자

살짝 봤는데 일단 소수 판별 코드가 잘 이해가 안 갑니다.

여기서 j = i*i를 하셨는데 i가 100만 까지 가는 상황이라 필연적으로 overflow가 일어납니다.
실제로 제 환경에서는 크래시가 나네요.

essenger M님의 프로필 이미지
essenger M

작성한 질문수

질문하기