sliver__

[Mastering C++ Programming] - Thread Synchronization 본문

CS/C++

[Mastering C++ Programming] - Thread Synchronization

sliver__ 2022. 12. 8. 23:23
728x90
  • 스레드는 더 나은 애플리케이션 성능을 제공합니다. 
  • 그러나 다중 스레드로 인해 애플리케이션 성능이 저하되는 것을 인지하는 것은 드문 일이 아닙니다. 
  • 이 성능 문제는 실제로 여러 스레드에 연결되어 있지 않을 수 있습니다. 
  • 진짜 범인은 디자인일 수 있습니다. 
  • 동기화를 너무 많이 사용하면 응용 프로그램 성능 저하를 유발하는 많은 스레드 관련 문제가 발생합니다.

  • Lock-free 스레드 설계는 스레드 관련 문제를 방지할 뿐만 아니라 전체 애플리케이션 성능을 향상시킵니다. 
  • 그러나 실제 세계에서는 둘 이상의 스레드가 하나 이상의 공통 리소스를 공유해야 할 수 있습니다. 
  • 따라서 공유 리소스에 액세스하거나 수정하는 코드의 중요 섹션을 동기화해야 합니다. 
  • 특정 시나리오에서 사용할 수 있는 다양한 동기화 메커니즘이 있습니다. 

 

[Synchronization이 이루어지지 않는다면?]

  • 프로세스 경계 내에서 공통 리소스를 공유하는 여러 스레드가 있는 경우 코드의 중요 섹션을 뮤텍스 잠금과 동기화할 수 있습니다. 
  • 뮤텍스는 하나의 스레드만 뮤텍스로 보호되는 중요한 코드 블록에 액세스할 수 있도록 하는 상호 배타적인 잠금입니다. 
  • 뮤텍스 잠금 애플리케이션의 필요성을 실질적으로 이해하기 위해 간단한 예를 들어 보겠습니다.

  • 세 가지 간단한 작업, 즉 getBalance, 인출 및 입금을 허용하는 은행 저축 계좌 클래스를 살펴보겠습니다. 
  • Account 클래스는 다음 코드와 같이 구현할 수 있습니다. 
  • 설명을 위해 Account 클래스는 현실 세계에서 필요한 코너 케이스 및 유효성 검사를 무시하는 간단한 방식으로 설계되었습니다. 
  • 계정 클래스가 계정 번호를 캡처하지 않아도 될 정도로 단순화되었습니다.
  • 단순함을 위해  무시되는 요구 사항이 많이 있다고 확신합니다.
#include <iostream>
using namespace std;

class Account {
private:
  double balance;
public:
  Account( double );
  double getBalance( );
  void deposit ( double amount );
  void withdraw ( double amount ) ;
};
#include "Account.h"

Account::Account(double balance) {
  this->balance = balance;
}

double Account::getBalance() {
  return balance;
}

void Account::withdraw(double amount) {
  if ( balance < amount ) {
    cout << "Insufficient balance, withdraw denied." << endl;
    return;
  }

  balance = balance - amount;
}

void Account::deposit(double amount) {
  balance = balance + amount;
}
#include <thread>
#include "Account.h"
using namespace std;

enum ThreadType {
  DEPOSITOR,
  WITHDRAWER
};

Account account(5000.00);

void threadProc ( ThreadType typeOfThread ) {

  while ( 1 ) {
  switch ( typeOfThread ) {
    case DEPOSITOR: {
      cout << "Account balance before the deposit is "
           << account.getBalance() << endl;

      account.deposit( 2000.00 );

      cout << "Account balance after deposit is "
           << account.getBalance() << endl;
      this_thread::sleep_for( 1s );
}
break;

    case WITHDRAWER: {
      cout << "Account balance before withdrawing is "
           << account.getBalance() << endl;

      account.deposit( 1000.00 );
      cout << "Account balance after withdrawing is "
           << account.getBalance() << endl;
      this_thread::sleep_for( 1s );
    }
    break;
  }
  }
}

int main( ) {
  thread depositor ( threadProc, ThreadType::DEPOSITOR );
  thread withdrawer ( threadProc, ThreadType::WITHDRAWER );

  depositor.join();
  withdrawer.join();

  return 0;
}
  • WITHDRAWER와 DEPOSITOR 스레드가 모두 잔액을 확인한 것으로 보이며 INR 9000.00이었습니다. 
  • DEPOSITOR 스레드의 인쇄 문에 불일치가 있음을 알 수 있습니다.
  • DEPOSITOR 스레드에 따라 현재 잔액은 INR 9000.00입니다. 
  • 따라서 INR 2000.00을 입금할 때 잔액은 총 INR 11000.00이 되어야 합니다. 
  • 그러나 실제로 입금 후 잔액은 INR 10000.00입니다. 
  • 이러한 불일치의 이유는 DEPOSITOR 스레드가 돈을 입금하기 전에 WITHDRAWER 스레드가 INR 1000.00을 인출했기 때문입니다. 기술적으로는 균형이 올바르게 된 것처럼 보이지만 곧 잘못될 수 있습니다. 
  • 이것은 스레드 동기화가 필요한 때입니다.
728x90
Comments