작성
·
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
1
lock_guard<SpinLock> lock(spinLock);
cnt++;
이 부분에서 cnt가 애당초 atomic이기 때문에
굳이 위와 같이 락을 잡을 이유가 없습니다.
그리고 경합이 많아질 수록 당연히 성능도 떨어질 수밖에 없습니다.
각자 count 계산을 다 하고, 최종 결과만을 cnt에다 더해주면
경합없이 동작시킬 수 있는데 굳이 1을 더할 때마다 경합을 할 필욘 없겠죠.
0
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
0
살짝 봤는데 일단 소수 판별 코드가 잘 이해가 안 갑니다.
여기서 j = i*i를 하셨는데 i가 100만 까지 가는 상황이라 필연적으로 overflow가 일어납니다.
실제로 제 환경에서는 크래시가 나네요.