Programing

const는 C ++ 11에서 스레드 안전을 의미합니까?

crosscheck 2020. 7. 22. 08:06
반응형

const는 C ++ 11에서 스레드 안전을 의미합니까?


C ++ 11 에서 스레드 안전const의미 한다고 들었습니다 . 그게 사실입니까?

그 의미 하는가 const에 해당 이제 자바synchronized?

키워드가 부족 합니까?


C ++ 11 에서 스레드 안전const의미 한다고 들었습니다 . 그게 사실입니까?

그것은이다 다소 사실 ...

이것이 스레드 안전성에 대한 표준 언어의 말입니다.

[1.10 / 4] 두 식 평가중 하나가 메모리 위치를 수정하고 (1.7) 다른식이동일한 메모리 위치에 액세스하거나 수정하면 충돌이 발생 합니다.

[1.10 / 21] 다른 스레드에서 충돌하는 두 가지 동작이 포함 된 경우프로그램 실행에 데이터 레이스 가 포함됩니다. 그 중 하나는 원자 적이 지 않으며 다른 것보다 먼저 발생하지 않습니다. 이러한 데이터 경쟁은 정의되지 않은 동작을 초래합니다.

이는 데이터 레이스 가 발생 하기에 충분한 조건 일뿐입니다.

  1. 주어진 일에 대해 두 가지 이상의 동작이 동시에 수행되고 있습니다.
  2. 그들 중 적어도 하나는 글입니다.

표준 라이브러리는 조금 더가는, 그 기반으로 :

[17.6.5.9/1] 이 섹션은 구현이 데이터 경쟁을 방지하기 위해 충족 해야하는 요구 사항을 지정합니다 (1.10). 달리 명시되지 않는 한 모든 표준 라이브러리 기능은 각 요구 사항을 충족해야합니다. 구현시 아래 명시된 사항 이외의 경우 데이터 경쟁을 막을 수 있습니다.

[17.6.5.9/3] C ++ 표준 라이브러리 함수 는를 포함 하여 함수의 비 const 인수를 통해 개체에 직접 또는 간접적으로 액세스하지 않는 한 현재 스레드 이외의 스레드가 액세스 할 수있는 개체 (1.10)를 직접 또는 간접적으로 수정해서는 안됩니다this.

간단히 말하면 const객체에 대한 작업 스레드로부터 안전하다고 기대합니다 . 즉, 표준 라이브러리const자체 유형의 객체에 대한 작업을 수행하는 한 데이터 레이스를 도입하지 않습니다.

  1. 완전히 읽기로 구성됩니다. 즉, 쓰기가 없습니다. 또는
  2. 내부적으로 쓰기를 동기화합니다.

이러한 기대가 귀하의 유형 중 하나에 해당되지 않는 경우, 표준 라이브러리의 구성 요소와 함께 직간접 적으로 사용 하면 데이터 경쟁 이 발생할 수 있습니다 . 결론적으로 표준 라이브러리 관점 에서 스레드 안전const의미 합니다 . 이것은 계약일 뿐이며 컴파일러에 의해 시행되지는 않습니다 . 계약 을 어기면 정의되지 않은 동작이 발생 하며 사용자가 스스로 처리해야합니다. 존재 여부 는 코드 생성에 영향을 미치지 않습니다 (적어도 데이터 레이스 와 관련하여) .const

그 의미 하는가 const에 해당 이제 자바synchronized?

없음 . 전혀...

사각형을 나타내는 다음과 같이 지나치게 단순화 된 클래스를 고려하십시오.

class rect {
    int width = 0, height = 0;

public:
    /*...*/
    void set_size( int new_width, int new_height ) {
        width = new_width;
        height = new_height;
    }
    int area() const {
        return width * height;
    }
};

멤버 함수는 area 이다 스레드 안전성 ; 그것의 때문이 const아니라 전적으로 읽기 작업으로 구성되기 때문입니다. 관련된 쓰기가 없으며 데이터 레이스 가 발생하려면 적어도 하나의 쓰기가 필요 합니다. 즉, area원하는 수만큼 스레드에서 호출 할 수 있으며 항상 올바른 결과를 얻을 수 있습니다.

이 것을 의미하지 않음을 참고 rect스레드 안전 . 사실, 그 쉬운에 대한 호출이있는 경우 방식을 볼 수 area있었다를 호출하는 것과 같은 시간에 일이 set_size주어진에가 rect, 다음 area(깨진 값도 이상) 오래된 폭과 새로운 높이에 따라 그 결과를 계산 끝낼 수 있었다 .

그러나 확실히하다, rect아니다 const는 심지어 않을 것으로 예상 있도록 스레드 안전 결국. 객체는 선언 된 const rect반면에, 것, 스레드 안전 에는 쓰기가 가능하지 않기 때문에 (그리고 당신이 고려하는 경우 const_cast원래 선언 뭔가 -ing const당신이 얻을 정의되지 않은-행동을 하고 그것 뿐이다).

그렇다면 그것은 무엇을 의미합니까?

Let's assume --for the sake of argument-- that multiplication operations are extremely costly and we better avoid them when possible. We could compute the area only if it is requested, and then cache it in case it is requested again in the future:

class rect {
    int width = 0, height = 0;

    mutable int cached_area = 0;
    mutable bool cached_area_valid = true;

public:
    /*...*/
    void set_size( int new_width, int new_height ) {
        cached_area_valid = ( width == new_width && height == new_height );
        width = new_width;
        height = new_height;
    }
    int area() const {
        if( !cached_area_valid ) {
            cached_area = width;
            cached_area *= height;
            cached_area_valid = true;
        }
        return cached_area;
    }
};

[If this example seems too artificial, you could mentally replace int by a very large dynamically allocated integer which is inherently non thread-safe and for which multiplications are extremely costly.]

The member-function area is no longer thread-safe, it is doing writes now and is not internally synchronized. Is it a problem? The call to area may happen as part of a copy-constructor of another object, such constructor could have been called by some operation on a standard container, and at that point the standard library expects this operation to behave as a read in regard to data races. But we are doing writes!

As soon as we put a rect in a standard container --directly or indirectly-- we are entering a contract with the Standard Library. To keep doing writes in a const function while still honoring that contract, we need to internally synchronize those writes:

class rect {
    int width = 0, height = 0;

    mutable std::mutex cache_mutex;
    mutable int cached_area = 0;
    mutable bool cached_area_valid = true;

public:
    /*...*/
    void set_size( int new_width, int new_height ) {
        if( new_width != width || new_height != height )
        {
            std::lock_guard< std::mutex > guard( cache_mutex );

            cached_area_valid = false;
        }
        width = new_width;
        height = new_height;
    }
    int area() const {
        std::lock_guard< std::mutex > guard( cache_mutex );

        if( !cached_area_valid ) {
            cached_area = width;
            cached_area *= height;
            cached_area_valid = true;
        }
        return cached_area;
    }
};

Note that we made the area function thread-safe, but the rect still isn't thread-safe. A call to area happening at the same time that a call to set_size may still end up computing the wrong value, since the assignments to width and height are not protected by the mutex.

If we really wanted a thread-safe rect, we would use a synchronization primitive to protect the non-thread-safe rect.

Are they running out of keywords?

Yes, they are. They have been running out of keywords since day one.


Source: You don't know const and mutable - Herb Sutter

참고URL : https://stackoverflow.com/questions/14127379/does-const-mean-thread-safe-in-c11

반응형