KR20220083036A - 시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법 - Google Patents

시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법 Download PDF

Info

Publication number
KR20220083036A
KR20220083036A KR1020200172853A KR20200172853A KR20220083036A KR 20220083036 A KR20220083036 A KR 20220083036A KR 1020200172853 A KR1020200172853 A KR 1020200172853A KR 20200172853 A KR20200172853 A KR 20200172853A KR 20220083036 A KR20220083036 A KR 20220083036A
Authority
KR
South Korea
Prior art keywords
pointer
thread
based memory
local
technique
Prior art date
Application number
KR1020200172853A
Other languages
English (en)
Other versions
KR102546947B1 (ko
Inventor
강지훈
정재황
Original Assignee
한국과학기술원
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by 한국과학기술원 filed Critical 한국과학기술원
Priority to KR1020200172853A priority Critical patent/KR102546947B1/ko
Priority to JP2021098267A priority patent/JP7214254B2/ja
Priority to PCT/KR2021/008456 priority patent/WO2022124507A1/ko
Priority to US17/510,149 priority patent/US20220187986A1/en
Publication of KR20220083036A publication Critical patent/KR20220083036A/ko
Application granted granted Critical
Publication of KR102546947B1 publication Critical patent/KR102546947B1/ko

Links

Images

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F3/00Input arrangements for transferring data to be processed into a form capable of being handled by the computer; Output arrangements for transferring data from processing unit to output unit, e.g. interface arrangements
    • G06F3/06Digital input from, or digital output to, record carriers, e.g. RAID, emulated record carriers or networked record carriers
    • G06F3/0601Interfaces specially adapted for storage systems
    • G06F3/0602Interfaces specially adapted for storage systems specifically adapted to achieve a particular effect
    • G06F3/0604Improving or facilitating administration, e.g. storage management
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F12/00Accessing, addressing or allocating within memory systems or architectures
    • G06F12/02Addressing or allocation; Relocation
    • G06F12/0223User address space allocation, e.g. contiguous or non contiguous base addressing
    • G06F12/023Free address space management
    • G06F12/0253Garbage collection, i.e. reclamation of unreferenced memory
    • G06F12/0261Garbage collection, i.e. reclamation of unreferenced memory using reference counting
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F12/00Accessing, addressing or allocating within memory systems or architectures
    • G06F12/02Addressing or allocation; Relocation
    • G06F12/0223User address space allocation, e.g. contiguous or non contiguous base addressing
    • G06F12/023Free address space management
    • G06F12/0253Garbage collection, i.e. reclamation of unreferenced memory
    • G06F12/0269Incremental or concurrent garbage collection, e.g. in real-time systems
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F12/00Accessing, addressing or allocating within memory systems or architectures
    • G06F12/02Addressing or allocation; Relocation
    • G06F12/0223User address space allocation, e.g. contiguous or non contiguous base addressing
    • G06F12/023Free address space management
    • G06F12/0253Garbage collection, i.e. reclamation of unreferenced memory
    • G06F12/0269Incremental or concurrent garbage collection, e.g. in real-time systems
    • G06F12/0276Generational garbage collection
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F3/00Input arrangements for transferring data to be processed into a form capable of being handled by the computer; Output arrangements for transferring data from processing unit to output unit, e.g. interface arrangements
    • G06F3/06Digital input from, or digital output to, record carriers, e.g. RAID, emulated record carriers or networked record carriers
    • G06F3/0601Interfaces specially adapted for storage systems
    • G06F3/0628Interfaces specially adapted for storage systems making use of a particular technique
    • G06F3/0655Vertical data movement, i.e. input-output transfer; data movement between one or more hosts and one or more storage devices
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F3/00Input arrangements for transferring data to be processed into a form capable of being handled by the computer; Output arrangements for transferring data from processing unit to output unit, e.g. interface arrangements
    • G06F3/06Digital input from, or digital output to, record carriers, e.g. RAID, emulated record carriers or networked record carriers
    • G06F3/0601Interfaces specially adapted for storage systems
    • G06F3/0668Interfaces specially adapted for storage systems adopting a particular infrastructure
    • G06F3/0671In-line storage system
    • G06F3/0673Single storage device
    • G06F3/0679Non-volatile semiconductor memory device, e.g. flash memory, one time programmable memory [OTP]
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F2212/00Indexing scheme relating to accessing, addressing or allocation within memory systems or architectures
    • G06F2212/10Providing a specific technical effect
    • G06F2212/1008Correctness of operation, e.g. memory ordering
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F2212/00Indexing scheme relating to accessing, addressing or allocation within memory systems or architectures
    • G06F2212/10Providing a specific technical effect
    • G06F2212/1016Performance improvement
    • G06F2212/1024Latency reduction
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F2212/00Indexing scheme relating to accessing, addressing or allocation within memory systems or architectures
    • G06F2212/72Details relating to flash memory management
    • G06F2212/7205Cleaning, compaction, garbage collection, erase control

Landscapes

  • Engineering & Computer Science (AREA)
  • Theoretical Computer Science (AREA)
  • Physics & Mathematics (AREA)
  • General Engineering & Computer Science (AREA)
  • General Physics & Mathematics (AREA)
  • Human Computer Interaction (AREA)
  • Information Retrieval, Db Structures And Fs Structures Therefor (AREA)
  • Techniques For Improving Reliability Of Storages (AREA)

Abstract

다양한 실시예들은 시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법을 제공한다. 다양한 실시예들은, 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현하고, 상기 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행하도록 구성된다.

Description

시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법{COMPUTER SYSTEM FOR HYBRID OF EPOCH- AND POINTER-BASED MEMORY RECLAMATION, AND METHOD THEREOF}
다양한 실시예들은 시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법에 관한 것이다.
컴퓨터 CPU의 많은 코어를 효율적으로 사용하기 위해서는 많은 코어들이 동시에 접근할 수 있는 동시성 자료구조를 사용해야 한다. 동시성 자료구조는 여러 스레드(thread)에서 동시에 자료를 넣고 뺄 수 있는 자료구조를 뜻한다. 동시성 자료구조는 여러 스레드의 상호작용을 한꺼번에 고려하고 규율해야 하기 때문에 한 스레드만 접근할 수 있는 순차적 자료구조보다 훨씬 더 복잡하다. 특히 메모리 수집에 대해 그러한데, 왜냐하면 동시성 자료구조에서는 한 스레드가 자료를 뺀 이후에도 다른 스레드에서 자료에 접근할 수 있기 때문이다. 다른 스레드에서 절대로 자료에 접근할 수 없음을 확인한 이후에야 자료를 가지고 있던 메모리를 수집할 수 있다.
동시성 자료구조 메모리 수집은 매우 어려운 문제이기 때문에, 이 문제만을 해결하는 다양한 기법이 제안되었다. 가장 유명한 기법은 포인터 기반 메모리 수집 기법(pointer-based memory reclamation)과 시대 기반 메모리 수집 기법(epoch-based memory reclamation)이다. 포인터 기반 수집 기법은 메모리 사용량이 적고, 메모리를 빠짐없이 수집할 수 있는 장점이 있지만, 느리고, 많은 자료구조에 적용할 수 없는 단점이 있다. 반면, 시대 기반 수집 기법은 메모리 사용량이 적고, 빠르고, 많은 자료구조에 적용할 수 있는 장점이 있지만, 메모리를 빠짐없이 수집할 수 없다는 단점이 있다.
다양한 실시예들은, 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여 두 기법의 장점을 모두 보유한 수집 기법을 제공한다. 다양한 실시예들에 따른 포인터 및 시대 기반 메모리 수집 기법(pointer-and-epoch-based memory reclamation; PEBR)은 두 기법의 알고리즘을 혼합하여 메모리 사용량이 적고, 빠르고, 많은 자료구조에 적용할 수 있고, 메모리를 빠짐없이 수집할 수 있다.
다양한 실시예들에 따른 컴퓨터 시스템에 의한 방법은, 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계, 및 상기 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행하는 단계를 포함할 수 있다.
다양한 실시예들에 따른 컴퓨터 시스템은, 메모리, 및 상기 메모리와 연결되고, 상기 메모리에 저장된 적어도 하나의 명령을 실행하도록 구성된 프로세서를 포함하고, 상기 프로세서는, 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현하고, 상기 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행하도록 구성될 수 있다.
다양한 실시예들에 따른 비-일시적인 컴퓨터-판독 가능 저장 매체는, 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계, 및 상기 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행하는 단계를 실행하기 위한 하나 이상의 프로그램들을 저장할 수 있다.
다양한 실시예들은, 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법이 혼합된 포인터 및 시대 기반 메모리 수집 기법을 이용하여, 메모리 사용량이 적고, 빠르고, 많은 자료구조에 적용할 수 있고, 메모리를 빠짐없이 수집할 수 있다.
도 1은 안전한 메모리 수집 방식이 없는, Treiber의 스택에서의 시나리오를 도시하는 도면이다.
도2는 안전하지 않은 수집을 갖는, Treiber의 스택을 도시하는 도면이다.
도 3은 시대 컨센서스 예시를 도시하는 도면이다.
도 4는 해저드 시대 컨센서스 예시를 도시하는 도면이다.
도 5는 다양한 실시예들에 따라 보호되는 Treiber의 스택을 도시하는 도면이다.
도 6은 다양한 실시예들에 따른 컴퓨터 시스템을 도시하는 도면이다.
도 7은 다양한 실시예들에 따른 컴퓨터 시스템에 의한 방법을 도시하는 도면이다.
이하, 본 문서의 다양한 실시예들이 첨부된 도면을 참조하여 설명된다.
1. 개요
큐(queues), B-트리(trees), 해시 테이블(hash tables), 워크 스틸링(work-stealing) 데크(deques), 라덱스(radix) 트리 및 트라이(tries)를 포함한 모든 포인터 기반 동시성 데이터 구조는 안전한 메모리 수집 문제를 처리해야 한다. 메모리 블록을 수집하기 전에 스레드가 나중에 참조 해제될 수 있는 블록으로 로컬 포인터를 고정하지 않아야 한다. 따라서 일반적으로 데이터 구조에서 분리된 메모리 블록을 즉시 수집해서는 안 된다.
예를 들어, Treiber의 스택을 고려해보자. 이 리스트는 기본적으로 헤드가 스택 상단인 요소의 링크된 리스트이다. 도 1에서와 같이, 스레드는 (i) 헤드에서 첫 번째 블록(커(cur)로 지칭됨)을 가로지르고, (ii) 커에서 두 번째 블록(넥스트(next)로 지칭됨)을 가로지르며, (iii) 헤드상 커에서 넥스트로 CAS(compare-and-swap)을 수행하여 커를 분리한다. 만약 (iv) 커가 즉시 수집된다면 어떻게 되는가? 그러면 다른 스레드는 팝 작업 중간에 커 및 참조 해제 커의 다음 포인터를 위한 로컬 포인터를 가질 수 있으며, 따라서 use-after-free 상태가 발생할 수 있다. 이러한 오류를 방지하기 위해 스레드는 다른 모든 스레드가 참조를 완료할 때까지 커의 수집을 연기해야 한다. 메모리 수집을 연기하려면 일반적으로 안전한 메모리 수집을 계획하거나 메모리 블록을 수집하는 것이 안전한 시기를 감지하는 라이브러리 또는 런타임 시스템에 의해 처리되는 여러 스레드의 중대한 협력이 필요하다. 그러한 방식 덕분에 데이터 구조 작성자는 그 운영에 집중할 수 있으며, (대부분의) 안전 메모리 수집 의무를 기본 방식에 맡길 수 있다.
이전에 서로 다른 절충의 많은 수집 방식이 제안되어 왔다. 그러나, 불행히도 이전의 어떤 방식도 동시에 다음과 같은 원하는 속성을 만족시키지 못한다. 견고성: 비협조적인 스레드는 다른 스레드가 무한히 많은 블록을 수집하는 것을 방해하지 않는다. 빠른 속도: 공유 메모리에 대한 각 참조에 대한 값비싼 펜스 동기화 때문에 상당한 시간 오버헤드가 발생하지 않는다. 컴팩트: 블록별 메타데이터 등으로 인해 상당한 공간 오버헤드가 발생하지 않는다. 자기충족: 특수 하드웨어/OS 지원에 의존하지도 않고 실행 환경(예: 인터럽트 핸들러 설치)에도 영향을 주지 않는다. 광범위하게 적용 가능: 큰 제약 없이 다양한 데이터 구조를 지원한다.
트레이싱(tracing) 가비지 콜렉터(gabage collector; GC)는 트레이싱이 높고 예측 불가능한 시간(대기 시간)과 공간(메모리 사용) 오버헤드를 유발하기 때문에 빠르지도 작지도 않다. 특히 메모리가 크거나, 업무량으로 리소스가 부족하거나, GC 런타임 자체를 구현해야 하는 경우 문제가 있다. 더욱이, GC가 견고해지려면, 대상 언어는 Java나 Haskell과 같이 형식적으로 안전해야 한다.
해저드 포인터(hazard pointer; HP) 및 패스 더 벅(pass-the-buck)과 같은 포인터 기반 수집 방식(pointer-based reclamation schemes; PBR)은 공유 메모리에 대한 각 참조가 읽기-애프터-쓰기(read-after-write; RAW) 동기화를 필요로 하기 때문에 빠르지 않다. 즉, 이전 쓰기 후 읽기를 주문하기 위해 값비싼 펜스를 삽입해야 한다. Drop-the-anchor는 PBR의 동기화 비용을 크게 절감하지만, 현재는 리스트에만 적용 가능하다. 더욱이 PBR은 Harris의 리스트와 Harris-Herlihy-Shavit의 리스트를 지원하지 않는다는 점에서 광범위하게 적용되지는 않는다. 비협조적인(non-cooperative) 스레드가 시대 발전(논리 타임 스탬프)을 차단하여 대부분의 블록이 재생되는 것을 막을 수 있기 때문에 시대 기반 수집 방식(epoch-based reclamation schemes; EBR)은 견고하지 않다.
빠르고 견고한 수집을 위해 HP와 EBR의 혼합이 제안되었다. Hazard Eras와 인터벌 기반 수집(interval-based reclamation; IBR)은 HP의 아이디어를 채택하여 비협조적인 스레드의 효과를 제한하는 EBR의 변형이지만 블록당 런타임 메타데이터로 인해 컴팩트하지 않다. QSense는 HP와 EBR의 혼합으로서 작업량에 따라 서로 전환하지만, OS 스케줄링의 시간적 제어에 의존하여 자급자족하지 않다.
본 개시에서는 PEBR을 제시하는데, PEBR은 위의 모든 속성을 만족시키는 최초의 안전한 메모리 수집 방안이다. PEBR은 Snowflake의 HP와 EBR의 혼합 디자인에서 영감을 얻어, 대부분 견고하고(HP와 같이), 빠르다(EBR과 같이). Snowflake는 블록당 공간 오버헤드가 발생하지 않는다는 점에서도 콤팩트하다. 그러나, Snowflake는 디자인이 GC와 긴밀하게 결합되어 있다는 점에서 자기 충족하지 않는다. 애당초 Snowflake의 주된 동기는 .NET Core의 GC 런타임에 수동 메모리 수집을 선택적으로 제공하는 것이다. 더욱이, Snowflake는 GC와의 안전한 상호작용으로 요구되는 제한된 프로그래밍 API 때문에 대부분의 포인터 기반의 비차단 데이터 구조에는 적용되지 않는다. 결정적으로 Snowflake는 메모리 블록에 대한 포인터 앨리어싱(aliasing)을 지원하지 않는다. 마지막으로, Snowflake의 이젝션(ejection) 알고리즘은 그것의 이젝션 알고리즘이 잠금장치에 의해 보호되기 때문에 사실 엄격한 의미에서는 견고하지 않다.
PEBR도 HP와 EBR의 빠르고 콤팩트한 혼합이지만 위에서 논의한 Snowflake의 한계가 없다. PEBR은 GC에 의존하지 않는 경량 런타임을 채용하고 표준 C/C++ 동시 특성과 프로세스 전반의 메모리 펜스만을 필요로 한다는 점에서 자기 충족하며, 그 중 후자는 Linux와 Windows의 사용자 공간 프로그램에 널리 이용 가능하다. PEBR은 견고하다. 특히, 본 개시는 비차단 이젝션 알고리즘을 설계한다. 가장 중요한 것은 PEBR이 포인터 앨리어싱, 포인터 태그 지정 및 읽기-수정-쓰기(read-modify-write; RMW) 작업(예: CAS 및 가져오기-추가(fetch-and-add))과 같이 동시 프로그래밍에 널리 사용되는 포인터 작업을 허용한다는 점에서 PEBR이 광범위하게 적용된다는 점이다. 또한 Harris와 Harris-Herlihy-Shavit의 리스트 등 다양한 비차단 데이터 구조로 충족되는 PEBR의 안전한 수집 요건도 특성화한다.
본 개시는 Rust로 작성된 EBR 구현인 Crossbeam 위에 PEBR을 구현했다. 본 개시의 구현은 공개적으로 가능하다. PEBR이 빠르고 견고한지 실험적으로 평가하기 위해, 본 개시는 Harris, Harris-Michael, Harris-Herlihy-Shavit, Michael의 해시 맵, Natarajan-Mittal 트리와 같은 여러 데이터 구조 마이크로벤치마크를 사용하여 성능을 EBR 및 NR과 비교하는 실험이 진행되었다. 해당 실험에서 PEBR은 EBR(처리량 감소 15% 미만으로 감소)과 비교할 수 없을 정도로 빠른 한편 견고했다(적대 환경에서도 성공적으로 메모리를 수집함).
본 개시의 나머지 부분에서는 PEBR을 상세히 설명하고 평가한다. 먼저 PBR, EBR, Snowflake와 같은 PEBR의 설계에 영감을 주는 이전 수집 방식을 검토하고, PEBR의 요구사항을 제시하며, 일부 요구사항을 자동으로 보장하는 높은 수준의 API를 제시하며, 비차단 이젝션 알고리즘을 포함한 PEBR의 알고리즘을 설명하고, PEBR의 속성을 논의한다.
2. 이전 수집 방식
Treiber 스택을 실행 예제(
Figure pat00001
2.1)로 사용하여 이전 방식이 use-after-free 오류를 방지하는 방법을 설명하고, 그 단점(
Figure pat00002
2.2부터
Figure pat00003
2.4)에 대해 논의한다.
2.1. 예제: Treiber 스택
도 2는 비안전 회복을 한 Treiber 스택을 보여준다. Treiber 스택이 기본적으로 스택 탑이 되는 헤드가 있는 요소의 링크된 리스트라는 것을 위에서 설명했다. (라인1 또는 L1) 구조 노드<T>는 데이터와 다음 포인터로 구성된 링크된 리스트 노드를 나타낸다. (L2-3) 스택<T>는 기본적으로 노드<T>에 대한 원자 포인터로서, 초기에는 nullptr이다. (L4-10) 푸시 방법은 현재의 헤드를 다음 포인터로 가리키는 새로운 노드를 생성하고, 현재의 헤드에서 새로운 노드로의 CAS를 수행한다. 그렇게 함으로써, 참조를 위한 메모리 공유를 위해 포인터 this-> head의 로컬 카피 커를 만든다. (L11-22) 반면에 pop 방법은 현재 헤드를 로드하여 로컬 포인터 커를 만들고, nullptr이 아닌 경우에는 다음 포인터를 읽고 현재 노드에서 다음 노드로 헤드에 CAS를 수행한다. (L9,20) 푸시 및 팝 방식 모두 CAS가 성공할 때까지 재시도한다.
상술된 바와 같이, pop(L18)에서는 (L16) 또 다른 스레드가 동시에 커->넥스트를 읽고 use-after-free 오류를 유발할 수 있으므로, 커를 분리한 후 즉시 수집하는 것은 안전하지 않다. 이 섹션의 나머지 부분에서는 수집 방법으로 로컬 포인터 참조를 보호하여 이러한 오류를 방지하는 방법을 설명한다.
2.2. 해저드(hazard) 포인터
먼저 초기 및 가장 기본적인 PBR 방식 중 하나인 해저드 포인터(HP) 방식을 설명한다.
API: HP는 다음과 같은 함수를 제공한다.
· protect(l): 공유 메모리에 지정된 로컬 포인터(l)를 보호. 보호된 로컬 포인터만 참조 해제되어야 한다. 호출 스레드의 보호된 포인터 리스트(또는 "해저드 포인터" 리스트)에 l을 추가한다. 보호 후 사용자는 l을 읽는 공유 위치에 l이 여전히 포함되어 있는지 검증해야 한다.
· unprotect(l): 보호된 포인터 리스트에서 l을 제거하여 l의 보호를 해제한다.
· retire(l): 참조 l의 수집 요청. 사용자는 포인터가 연결되지 않았는지(언링크), 즉 포인터를 폐기하기 전에 공유 메모리에 더 이상 존재하지 않는지 확인해야 한다. 언링크의 정확한 정의는
Figure pat00004
3.3을 참조한다. 호출 쓰레드의 스레드 로컬 수집 리스트에 l을 추가한다.
· collect(): 더 이상 스레드에 의해 보호되지 않는, 즉 재생 리스트의 포인터가 스레드의 보호된 포인터 리스트에 없는 폐기된 블록을 수집. 사용자가 호출하거나 런타임 자체로 호출하여 견고성을 보장할 수 있다.
도 2에 제시된 Treiber 스택은 다음과 같이 변경된다.
· L16 이전에 protect(cur); if (this->head.load()!=cur) continue;를 삽입한다.
· L16 후 unprotect(cur)를 삽입한다.
· L18에서는 free(cur)를 retire(cur)로 대체한다.
이점: API 요건은 보호되고 사전에 검증되는 경우에만 해당 커가 (L16) 역참조되며, (L17,18) 커는 폐기되기 전에 공유 메모리에서 분리된다.
예를 들어, protect, retire 및 collect 간의 동기화로 인해 커의 use-after-free가 방지된다. 첫째, protect(cur)는 다음과 같이 진행한다.
P1. 스레드의 보호된 포인터 리스트에 커가 추가된다.
P2. 헤드->넥스트가 여전히 API가 요구하는 커를 포함하는지 확인한다.
둘째, 폐기 후 커는 다음과 같이 수집한다.
C1. retire(cur)에서 요구하는 대로 커가 더 이상 공유 메모리에 존재하지 않는다고 가정한다.
C2. 모든 스레드의 보호된 포인터 리스트를 읽는다.
C3. 어떤 스레드로도 보호되지 않는 경우 커를 수집한다.
이제 실행 순서에 따라 P1은 C2보다 먼저 발생하거나 C1은 P2보다 먼저 발생한다. 전자의 경우, 커는 보호되는 것으로 게시되어 C3에서 수집되지 않는다. 후자의 경우, 커는 더 이상 공유 메모리에 존재하지 않기 때문에 P2의 검증에 실패한다. 어느 경우든, 커에 대해 use-after-free가 절대 발생하지 않는다.
단점: 직관적이긴 하지만 HP는 값비싼 동기화 때문에 빠르지 않다. 위의 사례 분석이 이상이 없으려면 RAW-동기화 펜스를 발행하여 P1의 쓰기(및 C1)와 P2의 읽기(및 C2, 각각) 사이의 순서를 강제해야 한다. 특히 각 포인터 보호와 따라서 포인터 역참조에 대해 펜스가 발행되어야 한다. 더욱이 HP는 원본 HP 본 개시에서 논의한 바와 같이, 개별 포인터를 보호하는 능력이 Harris와 Harris-Herlihy-Shavit 리스트에서 반복적으로 지원하기에 충분하지 않다는 점에서 광범위하게 적용되지는 않는다(자세한 내용은
Figure pat00005
3.3 참조). 이러한 단점들은 EBR과 같은 다른 수집 방식에 동기를 부여한다.
2.3. 시대 기반 수집
Harris 버전, Fraser 버전, QSBR과 같은 EBR 방식은 한 번에 여러 개의 로컬 포인터를 보호하여 동기화 비용을 고려한다.
API: EBR은 다음과 같은 함수를 제공한다.
· set_active(), set_quiescent(): 스레드가 공유 메모리("활성 상태")에 액세스하고 있는지 아닌지("비활성 상태"): 사용자는 (i) 공유 메모리가 활성 상태 내에서만 액세스되는지 확인해야 하며, (ii) 공유 메모리를 읽음으로써 활성 상태에서 생성된 로컬 포인터는 비활성 상태로 전환되지 않고 동일한 활성 상태에서만 역참조되어야 한다.
· retire(l): l의 참조자 수집을 요청한다. HP와 유사한 요건을 가지고 있다. 또 활성 상태에서 호출해야 한다.
· collect(): 충분히 오래된 활성 상태의 폐기된 블록을 수집한다.
도 2에 제시된 Treiber의 스택은 다음과 같이 변경된다.
· L6, 13 이전에 set_active();를 삽입한다.
· L9, 20 후에 set_quiescent();를 삽입한다.
· L18에서는 free(cur)를 retire(cur)로 대체한다.
API 요건은 해당 커가 (L7,14) 활성 상태에서 재설정되고, (L16) 동일한 활성 상태에서 역참조되며, (L17,18) 활성 상태에서 폐기되기 전에 공유 메모리에서 분리되는 경우 충족된다.
이점: (i) 활성 스레드가 로컬 시대에 고정되어 있는 스레드 간의 시대 컨센서스 동기화를 통해 사후 사용을 방지하고, (ii) 동시 활성 스레드의 로컬 시대는 다를 수 있지만 너무 많이 기울어지지 않도록 보장하며, (iii) 충분한 시대에서 폐기한 포인터만 수집한다. 따라서, 수집된 블록은 현재 최근 시대에 고정된 활성 스레드에서 (역)참조될 수 없다.
보다 구체적으로, 도 3에 제시된 사례 이벤트 그래프를 보자. 여기서 노드는 이벤트를 나타내고 에지는 발생 전 관계를 나타낸다. B(e)와 E(e)는 활성 상태의 시작과 끝을 나타내며, 예를 들어 A(e)는 로컬 시대 e에 고정된다. 시대 컨센서스에서, 스레드는 협력적이고 주기적으로 글로벌 시대를 진전시키며, 그들의 e로의 진전은 G(e)로 표현된다. 글로벌 시대는 각 A(e)에 대해 (i) G(e)가 B(e)보다 먼저 일어나고 (ii) E(e)가 G(e + 2)보다 먼저 발생한다고 보장함으로써 로컬 시대의 너무 많은 왜곡을 방지한다. 활성 상태 A(e)에서는 e - 3 또는 그 이전에 고정된 활성 상태에서 폐기된 포인터만 수집한다.
시대는 실제로 use-after-free를 방지한다. 즉. 도 3의 b. 여기서 A(0)의 R(b)은 블록 b의 폐기를 나타낸다. A(1)의 D(b)는 b의 역참조이고, A(3)에서 F(b)는 b의 수집이다. 왜? (빨간색) 먼저 b가 R(b), E(0), G(2), B(2) 이전의 공유 메모리에서 연결되지 않기 때문에 2(또는 그 이후)에 고정된 활성 상태 내에서 b에 대한 로컬 포인터를 만들고 역참조할 수 없다. (파란색) 한편, A(1)(또는 그 이전) 내부, 예를 들어 D(b) 내부 b에 대한 역참조는 E(1), G(3), B(3), F(b)보다 먼저 일어난다.
시대는 RAW 동기화가 각 역참조 시에만 발생하는 것이 아니라 각 활성 상태의 시작 시에만 발생하기 때문에 동기화 비용을 크게 절감한다. 구체적으로는 HP의 P1(
Figure pat00006
2.2)과 같은 방식으로 시대 e가 보호되고 있다는 것을 게시하기 위해서는 B(e)에서 RAW 동기화가 필요하므로 글로벌 시대가 e+2로 진전되지 않는다.
단점: EBR은 빠르기는 하지만 비협조적 스레드가 활성 상태를 벗어나지 못할 수 있다는 점에서 견고하지 않기 때문에 글로벌 시대 진전을 차단하고 새로 폐기한 블록의 수집을 방지한다. 본질적으로, EBR은 한없이 많은 수의 로컬 포인터를 보호함으로써 빠르게 견고성을 거래한다. 견고성이 부족하기 때문에, 장기 실행 작업 보호(예: 객체 캐시 또는 OLAP 워크로드)에 EBR을 사용하는 것은 바람직하지 않다.
2.4. Snowflake
Snowflake는 HP와 EBR의 혼합물이다. 빠르고, 그것은 마치 초기 EBR처럼 작동한다. 강력하고 최대 메모리 사용량을 줄이기 위해, 비협조적 스레드를 활성 상태에서 비활성 상태로 이젝트하고 HP와 같이 각각의 로컬 포인터를 개별적으로 보호한다. 그런 다음 글로벌 시대를 앞당기고 폐기한 블록을 수집하여 견고성을 보장할 수 있다.
API: Snowflake는 HP와 거의 동일한 API를 가지고 있으며, 특히 사용자는 시대 컨센서스로 보호되고 있음에도 불구하고 로컬 포인터를 폐기하기 전에 로컬 포인터를 보호해야 한다. 그 이유는 시대 컨센서스가 스레드를 이젝트하고 로컬 포인터의 보호를 취소할 수 있으며, 만약 그렇다면, 포인터는 HP를 통해 보호되어야 하기 때문이다. 결과적으로 보호 요건은 HP와 유사하지만 다음과 같이 약간 다르다.
· 활성 상태에서 생성된 로컬 포인터는 이젝트로 인한 비활성 상태로 전환하지 않고 동일한 활성 상태에서만 보호되어야 한다. 이 요구 사항을 활성 상태에서 생성된 로컬 포인터를 동일한 활성 상태에서 역참조해야 한다는 EBR 요건과 비교해보라.
· protect(l)에서, 보호 포인터 리스트에 l를 추가한 후, Snowflake는 스레드가 이젝트되지 않고 여전히 활성 상태인지 여부를 반환한다. 사용자는 포인터가 시대 컨센서스로 실제로 보호되도록 하기 위해 protect(l)을 폐기하기 전에 protect(l)의 반환 값을 검증해야 한다. 이 요건을 사용자가 l을 읽는 공유 위치에 여전히 l이 포함되어 있는지 검증할 HP와 비교해보라.
또한, Snowflake는 이젝트되는 스레드에 다시 가입하여 시대 컨센서스를 위해 set_active()를 제공한다. Snowflake는 set_quiescent()를 제공하지 않지만, API에 함수를 추가하는 것은 간단하다고 생각한다.
도 2에 제시된 Treiber 스택은 다음과 같이 변경된다.
· L16 이전에 if (!protect(cur)) {set_active(); continue; }를 삽입한다.
·L16 후에 unprotected(cur);를 삽입한다.
·L18에서는 free(cur)를 retire(cur)로 대체한다.
사용자가 this->head에서 다시 읽는 대신 protected(cur)의 반환 값을 확인하여 유효성을 검증한다는 점을 제외하면 HP의 변경은 동일하다.
이점: 이젝션이 없을 때, Snowflake는 EBR과 같은 방법으로 use-after-free 를 방지한다. 활성 상태 내부에서 생성된 로컬 포인터는 시대 컨센서스 덕분에 동일한 활성 상태 내에서 (보호 및) 비참조해도 안전하다.
스레드가 이젝트되더라도 (i) 보호 후 유효성 검사(l)는 활성 상태에서 스레드의 보호 포인터 리스트에 포인터가 추가되도록 보장하고, (ii) Snowflake의 이젝션 알고리즘은 활성 상태 중에 리스트에 추가된 포인터가 다른 스레드에 보이도록 하여 그들이 그것을 수집하지 않도록 한다. 후드 아래에서 스레드의 보호된 포인터는 활성 상태에서만 추적되며, 꺼낼 때만 다른 스레드에 게시된다. 이 알고리즘을 protect(l)이 포인터를 다른 스레드에 즉시 게시하는 HP와 비교해보라.
단점: Snowflake는 Snowflake의 주요 동기, 즉 NET Core [21]에서 수동 메모리 수집을 선택적으로 제공하는 제약으로 인해 대부분의 비차단 데이터 구조에는 적용되지 않는다. 구체적으로 말하자면 강력한 유형 안전성에 대한 NET Core의 요구사항은 다음과 같이 비차단 프로그래밍과 충돌한다.
첫째, Snowflake는 고유한 소유자 조건을 요구한다. 수동으로 관리되는 블록은 최대 한 명의 소유자가 가리켜야 한다(각 스레드의 로컬 포인터 제외). 결과적으로, Snowflake는 동시성 데이터 구조에서 여러 포인터를 별칭으로 지정하는 것을 금지한다. 이 요건은 강력한 유형 안전성에 의해 동기가 부여된다. 본질적으로, 이 조건에서는 블록이 그것의 단일 소유자에 의해 포기되는 즉시, 블록은 HP의 C1(
Figure pat00007
2.2)과 유사한 폐기 요건을 자동으로 충족한다. 그러나 가장 기본적인 비차단 데이터 구조 중 하나인 Treiber 스택에서도 만족하지 못하며, 도 1에서 CAS에 성공한 후 헤드와 커의 참조자가 별칭과 동시에 다음을 가리킨다.
둘째, Snowflake의 API는 각 스레드의 로컬 포인터의 공유 메모리에 대한 사용에 상당한 문법 제약을 부과한다. 포인터 태깅 또는 포인터 정수 캐스팅[casting]은 지원하지 않는다. 또한 로컬 포인터는 해당 스레드 스택에만 상주해야 하며 스레드에서만 사용해야 한다. 이 요건은 또한 강력한 유형 안전성에 의해 동기가 부여된다. 실제로 로컬 포인터를 제한 없이 사용하면 활성 상태에서 수명이 연장되어 시대 컨센서스의 가정이 깨질 수 있다. 그러나 (i) 포인터 태깅과 포인터-정수 캐스팅이 Harris, Harris-Michael 및 Harris-Michael의 링크된 리스트를 포함한 다양한 데이터 구조에서 결정적으로 사용된다는 점에서 너무 제한적이다. (iii) 암시적 박싱의 경우 필요한 로컬 포인터를 힙으로 허용하지 않는다. (iiii) 다중 처리 비동기 작업 실행자에 필요한 다른 스레드에 의한 로컬 포인터의 사용을 허용하지 않는다.
더욱이, Snowflake의 이젝션 알고리즘은 잠금장치와 페이지 결함을 사용한다는 점에서 실제로 강력하지도, 자기 충족하지도 않다. 이젝션은 다음과 같이 진행된다. 스레드 A가 스레드 B를 이젝트할 때, (i) A가 B의 보호된 로컬 포인터를 열거하여 게시하고, B의 보호된 포인터 리스트의 권한을 읽기 전용으로 변경하고, B가 B의 "이젝션 잠금"을 잡고 이젝트되는 것으로 표시한다. (ii) B는 새로운 보호 로컬 포인터를 추적할 때 페이지 결함 예외를 통해 이젝트되는 것을 알아차리며 (iiii) 페이지 결함 핸들러에서, B는 이젝션 잠금장치를 잡고 이젝션으로부터 복구한다. 이 알고리즘은 비협조적 스레드 B가 스레드 A가 B의 이젝션 잠금장치를 잡고 있다가 잠길 때 배출되지 않을 수 있기 때문에 견고하지 않다. 또한 이 알고리즘은 사용자 정의 페이지 오류 핸들러를 설치하기 때문에 독립적이지 않다.
3. 요건
이하에서는, 먼저 Treiber의 스택을 예시(
Figure pat00008
3.1)로 사용한 PEBR의 API를 소개하고, 사용자가 만족해야 할 로컬 포인터와 폐기에 대한 요건을 제시하고(
Figure pat00009
3.2와
Figure pat00010
3.3, 각각) 적용성에 대해 논의한다(
Figure pat00011
3.4).
3.1. API
(1) PEBR의 API는 HP와 EBR의 API를 혼합하여 set_active(), protect(l), unprotect(l), retire(l), collect()를 제공하지만, 또한 시대 컨센서스에서 벗어나 자발적으로 선택하는 set_quiescent()도 제공한다. 사용자가 활성 상태를 더 짧게 유지할 수 있고 시대 진전과 블록 수집을 덜 방해할 수 있기 때문에 성능에 이롭다. 자발적으로 꺼낸 것인지 비자발적으로 꺼낸 것인지에 관계없이, 스레드는 보호되는 로컬 포인터를 폐기해도 안전하며, 따라서 여러 대기 상태에 걸쳐 있는 오래가는 포인터들을 지원한다. 도 2에 제시된 Treiber 스택은 다음과 같이 변경된다.L6, L13 이전에 set_active();를 삽입한다.
(2) L9, L20 후에 set_quiescent();를 삽입한다.
(3) L16 이전에 if (!protect(cur)) {set_active(); continue; }를 삽입한다.
(4) L16 후에 unprotected(cur);를 삽입한다.
(5) L18에서는 free(cur)를 retire(cur)로 대체한다.
그 변화는 EBR (1,2,5)의 그것과 Snowflake (3,4,5)의 혼합물이라는 것을 주목할 필요가 있다.
set_active()와 set_quiescent()로 활성 상태의 수명을 추적하는 동시에, 사용자에게 시대 컨센서스에 대한 보다 정확한 제어를 제공하는 동시에 API에 불가해한 복잡성을 추가한다. 복잡성을 완화하기 위해 PEBR은 높은 수준의 API(
Figure pat00012
4.1)를 제공한다. 또한 사용자는 스레드를 이젝트하지 않는 한 항상 활성 상태로 유지하도록 요구하여 복잡성을 완전히 제거할 수 있으며, 명시적으로 활성 상태의 수명을 추적해야 하는 부담에서 벗어날 수 있다.
제한된 수의 보호된 로컬 포인터 슬롯만 지원하는 대부분의 HP 구현과 달리, PEBR의 구현은 고정 길이 슬롯 배열의 링크된 리스트를 사용하여 정적으로 알려지지 않은 수의 슬롯을 지원한다. 이것은 Bonsai 트리와 같은 지원을 위해 필수적이다.
Figure pat00013
2.4에서 Snowflake가 로컬 포인터의 사용과 포인터의 앨리어싱에 대해 너무 엄격한 요건을 부과하여 비차단 데이터 구조에 대한 적용 가능성을 제한한다는 점을 상기해야 한다. 반면에 PEBR은 다음과 같이 안전한 수집을 위해 보다 완화된 요건을 요구한다.
3.2. 로컬 포인터의 요건
Snowlake와 달리 PEBR은 로컬 포인터를 자유롭게 태그 지정하거나 정수에 캐스팅하거나 힙에 저장하거나 다른 스레드에 사용할 수 있도록 허용하며, 다음의 요건들을 충족한다.
요건 3.1(보호). 스레드가 공유 메모리를 읽음으로써 l이라 하는 로컬 포인터를 만든다고 가정하자. 그러면 (i) 나중에 스레드만 보호할 수 있으며, (ii) set_active()는 그들 사이에서 호출되지 않는다.
보호(l)가 참(true)으로 반환되는 경우, 그 다음에는 보호 시점에 스레드가 활성 상태에 있고, 더 나아가 요건 3.1이 유지되는 경우 동일한 활성 상태에서 생성되어야 한다는 점을 상기해야 한다. 요건 3.1은 RAII 유형(
Figure pat00014
4.1과 4.2)에 기초한 높은 수준의 API에 의해 정적으로 보장된다.
HP와 Snowflake와 마찬가지로 PEBR은 모든 역참조가 이전에 성공적으로 보호되었어야 한다고 요구한다.
요건 3.2(역참조). 로컬 포인터 l을 참조하는 스레드를 가정해 보십시오. 그러면 protect(l)이 더 일찍 호출되고, 참이 반환되며, protect(l)가 unprotect(l)이 되어 l의 보호와 역참조 사이에 호출되지 않는다.
요건 3.2는 또한 높은 수준의 API (
Figure pat00015
4.1과 4.3)에 의해 정적으로 보장될 것이다. 요건 3.1과 3.2는 로컬 포인터가 활성 상태에서 생성되고 보호되는 경우에만 로컬 포인터가 참조 해제된다는 것을 의미한다.
protect(l)이 거짓을 반환하더라도 set_active()를 호출하여 해당 스레드가 새로운 활성 상태로 들어가 남은 작업을 재개할 수 있다는 점에 유의할 필요가 있다. 요건 3.1은 기존 로컬 포인터의 보호를 금지하지만, 요건 3.2는 스레드가 나머지 작업을 수행할 수 있는 새로운 로컬 포인터를 생성하기 위해 이미 보호된 로컬 포인터의 폐기를 허용한다.
3.3. 폐기에 관한 요건
Figure pat00016
2.4에서 Snowflake의 고유한 폐기 조건이 자동으로 폐기 요건을 충족하지만, 적용가능성도 크게 제한한다는 점을 상기한다. 한편, PEBR은 복수의 포인터를 별칭으로 할 수 있도록 허용하고, 그 대신에 광범위하게 적용되는 다음의 두 가지 폐기 요건을 부과한다.
첫 번째 요건은 폐기 전 공유 메모리에서 블록을 연결 해제해야 한다는 HP/EBR 요건과 유사하다.
요건 3.3(폐기). b를 블록으로 하자. 그런 다음 b는 최대 한 번에 폐기된다. 그리고 b가 폐기되기 전 공유 메모리에서 연결되지 않는다. 또는 더 구체적으로 폐기 이벤트 R(b)와 위치에 b의 포인터 값을 쓰는 모든 이벤트의 경우, 예를 들어 l은 다음과 같이 유지된다.
(i) w는 R(b)보다 먼저 발생하며,
(ii) w가 R(b)에 보이는 경우, R(b) 앞에 나타나는 blk(l)이 있고, 여기서 w는 R(b) 이후와 R(b) 이전에 발생하는 l에 대한 쓰기 이벤트가 없는 경우 R(b)에 표시되며, blk(l)는 l 위치를 포함하는 블록이다.
대략적으로 말하면, (i) 폐기한 블록에 대한 포인터를 공유 메모리에 다시 쓰지 않아야 한다는 의미와, (ii) 폐기한 블록을 가리키는 모든 블록도 공유 메모리에서 집단적으로 연결되지 않도록 폐기해야 한다는 것을 의미한다. 그것은
Figure pat00017
2에서 언급한 retire(l)에 필요한 연결 해제 및 포인터 존재에 대한 정확한 정의이다. HP와 EBR에도 동일한 요건이 적용된다. 그러나 요건 3.3은 Harris의 리스트의 다음 예와 같이 (HP 및) PEBR에 대한 안전한 수집을 보장하기에 충분하지 않다.
Figure pat00018
스레드 A가 논리적으로 삭제된 두 개의 노드를 하나의 CAS에 의해 연속적으로 분리 및 수집하고 있으며 스레드 B가 현재 첫 번째 노드를 통과 및 보호하고 있다고 가정하자. 요건 3.3만으로는 현재 보호되고 있지 않고 수집의 대상이기 때문에 두 번째 노드에 대한 use-after-free 사용을 방지할 수 없으며, 동시에 첫 번째 노드에서 B가 횡단하는 동안 역참조할 수 있다. 이러한 이유로 HP는 원래의 HP 본 개시에서 논의한 바와 같이 Harris 및 Harris-Herlihy-Shavit의 리스트와 근본적으로 호환되지 않는다. 이러한 오류를 방지하기 위해 PEBR은 두 번째 폐기 요건을 부과한다. 본질적으로 폐기한 블록(예: 첫 번째 노드)을 통과시켜 새로운 활성 상태에서 새 로컬 포인터를 생성하면 안 된다.
요건 3.4(폐기 블록 보호). b를 블록으로 하고, R(b)를 그것의 폐기 이벤트로 하고, P(b)를 b의 보호 이벤트로 하고, a를 활성 상태로 한다. R(b) 및 P(b)가 a보다 먼저 발생한다고 가정하고, a 내부에서는 b가 역참조되어 새 로컬 포인터 l을 생성한다고 가정하고, 이후 l은 보호되지 않는다.
PEBR에 의해 보호될 때 Harris의 리스트에 의해 만족된다. (i) 폐기하기 전에 노드는 논리적으로 삭제된 것으로 표시된다. 즉, "넥스트" 포인터는 태그가 지정되고, (ii) 논리적으로 삭제된 블록은 이후에 통과되지 않기 때문이다. Use-after-free는 실제로 방지된다. 예를 들어, 두 번째 노드를 재확보한 경우 스레드 B를 이젝트해야 하므로 요건으로 인해 두 번째 노드를 보호하고 역참조할 수 없다.
EBR이 특별히 그러한 조건을 필요로 하는 것은 이젝션을 하지 않기 때문이라는 점에 주목할 필요가 있다. 이와 관련하여, 요건 3.4를 이젝션이 존재하는 상황에서 폐기한 블록의 역참조에 대해 EBR의 시대-획기적 보호를 제공하는 조건이라고 생각할 수 있다.
3.4. 적용가능성
네 가지 요건은 Treiber의 스택에 의해 충족된다. 특히, 요건 3.3은 (i) L9에서 L14까지의 해제/수집 동기화를 통해 커 폐기 전 L8,9,17에서 모든 커 쓰기가 발생하기 때문에, 그리고 (ii) 모든 커 쓰기는 커가 폐기 전에 덮어쓰기 때문에, 그리고 요건 3.4는 모든 횡단이 단일 활성 상태 내에 있기 때문에 유지된다. 마찬가지로, 그들은 Harris-Michael의 리스트과 EBR이 지원하는 다른 동시성 데이터 구조에 의해 만족한다. 구체적으로, EBR에서 구현된 데이터 구조는 공유 메모리에 대한 각 역참조를 보호함으로써 PEBR에 포팅될 수 있다. 특히, EBR의 원래 구현이 요건 3.3을 만족하는 한, PEBR의 포팅된 구현은 요건 3.3과 요건 3.4를 추가로 만족시키고 있다.
PEBR은 대부분의 포인터 기반 비차단 데이터 구조로 충족되지 않는 고유한 소유자 조건을 요구하는 Snowflake보다 적용 가능성이 크다. 특히 PEBR은 암시적 박싱[boxing]과 비동기적 작업 실행기에서 포인터 공유 패턴을 지원한다. PEBR은 Harris와 Harris-Herlihy-Shavit의 리스트를 지원하지 않는 HP보다 엄격히 적용 가능하다. 게다가, 요건 3.1~3.4는 Harris와 Harris-Herlihy-Shavit의 리스트에 대해 검증된 수집 방식 요건의 첫 번째 특성이다.
4. 높은 수준의 API
Figure pat00019
3에 제시된 4가지 요건은 이전 방식에 비해 복잡하여 충족하기가 번거롭다. 이러한 어려움을 완화하기 위해, 본 개시는 요건 3.1과 3.2를 정적으로 검증하는 PEBR의 높은 수준의 API를 제시한다. 구체적으로, 활성 상태(
Figure pat00020
4.1)에 해당하는 RAII 유형을 사용하고, 로컬 포인터(
Figure pat00021
4.2)의 수명을 추적하기 위해 러스트의 소유권 기반 유형을 활용하는 데 Crossbeam을 따르고, 보호된 로컬 포인터(
Figure pat00022
4.3)에 해당하는 RAII 유형을 도입한다. 본 개시는 높은 수준의 API가 어떻게 Treiber 스택을 예시(
Figure pat00023
4.4)로 사용하여 요건 3.1과 3.2를 정적으로 보증하는지 설명한다.
4.1. Guard로 활성 상태 구분
본 개시는 RAII 유형인 Guard를 사용하여 활성 상태의 수명을 추적하는데 있어 Crossbeam을 따르며, 그 생성자와 소멸자는 각각 set_active()와 set_quiescent()를 사용한다.
Figure pat00024
그러나 Guard의 존재는 이젝트될 수 있기 때문에 활성 상태라는 것을 보장하지 않는다. 따라서 Guard가 여전히 활성 상태인지 확인하는 방법인 is_active()를 제공한다. 이 방법을 사용하면 다음과 같이 특정 코드 영역이 활성 상태에서 실행되도록 보장할 수 있다.
Figure pat00025
4.2. 로컬 포인터의 수명 추적
본 개시는 Rust의 소유권 기반 유형을 사용하여 로컬 포인터의 수명을 정적으로 추적하면서 다시 Crossbeam을 추적한다. 구체적으로, 'g에 유효한 로컬 포인터를 나타내는 새로운 유형인 Shared<g', T>를 소개한다.
Figure pat00026
Rust에서 주석으로 표시된 수명 'g는 정적 방식으로 Shared<'g, T> 값이 수명 'g보다 오래 지속되지 않고 로컬 포인터를 여러 개의 스레드에서도 여러 변수에 공유할 수 있다. 수명 'g는 Guard의 것을 의미하며, 그 결과 활성 상태 내에서 로컬 포인터(i)가 생성되고, (ii)는 이젝트되지 않는 한 동일한 활성 상태 내에서만 존재한다.
수명 제약조건은 다음 API에 의해 규정된다.
Figure pat00027
여기서, Atomic<T>는 T에 대한 포인터를 쥐고 있는 공유 원자 위치를 나타낸다. 이 유형은 원시 포인터 대신 PEBR 위에 구현된 동시성 데이터 구조 내부에 포인터 값을 저장하는 데 사용해야 한다. 그것의 기본 포인터 값은 비공개적이며 load와 cas와 같은 포인터 판독 방법을 통해서만 읽을 수 있다. 이러한 방법은 적어도 'g의 수명 동안 활성 상태인 Guard에 대한 참조가 제공되며, 반환된 로컬 포인터가 'g에만 유효함을 의미하는 Shared<g, T'>를 반환한다. 반면에 로컬 포인터는 Atomic<T>에 저장할 수 있다. store, cas와 같은 포인터 쓰기 방법을 사용한다. 이러한 방법은 로컬 포인터를 생성하지 않기 때문에 특별히 Guard에 대한 참조를 필요로 하지 않는다. 예를 들면 다음과 같다.
Figure pat00028
PEBR은 또한 폐기와 수집을 활성 상태 내에서 호출하여 그들이 시대와 동기화되도록 요구한다. 다시 말하지만, 본 개시는 Guard에게 다음 함수에 대한 참조를 제공함으로써 이것을 정적으로 보장한다.
Figure pat00029
4.3. 실드를 사용하여 로컬 포인터 보호
리스트에 슬롯을 소유한 RAII 유형 Shield<T>를 사용하여 각 스레드의 보호된 포인터 리스트를 유지 관리하는 Snowflake를 따른다.
Figure pat00030
그것의 생성자는 호출 스레드의 보호된 포인터 리스트에 슬롯을 예약한다. 구성된 후 실드는 (i) 해당 슬롯에 로컬 포인터를 작성하여 로컬 포인터를 보호할 수 있으며, 주어진 가드가 여전히 활성(즉, 이젝트되지 않음)인지 여부를 반환하거나, (ii) 슬롯에서 포인터를 지워 포인터의 보호를 해제하거나, (iii) 보호된 포인터를 역참조할 수 있다. 실드가 파괴되거나 다른 포인터를 보호하면 기존 포인터가 자동으로 보호되지 않는다.
실드는 실드의 소멸자에서 기본 로컬 포인터가 보호되지 않기 때문에 존재하는 한 실드는 역참조해도 안전하다. PEBR에서는 Rust의 소유 기반 타입 시스템으로 정적으로 검증한다. 적용가능성을 위해 실드를 여러 번, 그리고 Rust의 타입 시스템에 "Synched"로 표시하여 복수의 스레드에 의해서도 참조할 수 있도록 한다. 로컬 포인터가 해당 스레드 스택에 있어야 하며 스레드에서만 사용해야 한다는 Snowflake의 엄격한 요구 사항과 비교해보라. 단 보호된 포인터 리스트 슬롯은 독점적이고 스레드 로컬 리소스이기 때문에 본 개시는 실드가 Rust 유형 시스템의 다른 스레드에 "복사 가능"도 "보내기 가능"도 아닌 것으로 표시한다.
4.4. 모두 합하기
요건: 지금까지 도입된 높은 수준의 API는 집합적으로 요건 3.1과 3.2를 정적으로 보장한다. 요건 3.1은 활성 상태 내에서 생성된 로컬 포인터가 동일한 활성 상태 내에서만 보호되어야 함을 의미하며, 요건 3.2는 보호되는 로컬 포인터만 역참조됨을 의미한다. 첫째, 요건 3.1은 (i) Atomic의 API에서 요구하는 대로 가드의 수명 내에 로컬 포인터를 생성해야 하고, (ii) Shield의 API에서 요구하는 대로 동일한 가드의 수명 내에 로컬 포인터를 보호해야 하며, (iii) 내부의 유효성 확인 보호는 가드가 활성 상태에 해당한다는 것을 보장해야 하기 때문이다. 둘째, 요건 3.2는 실드의 API에서 직접 유지한다. 보호되는 로컬 포인터만 역참조할 수 있다.
적용가능성: 높은 수준의 API는 광범위하게 적용 가능하다. 예를 들어, 본 개시는 Treiber의 스택과 Harris, Harris-Michael, Harris-Herlihy-Shavit 리스트를 포함하여 평가에 사용한 모든 마이크로 벤치마크를 구현하기 위해 API를 사용했다.
사례: 도 5는 지금까지 소개된 API를 사용하여 PEBR로 보호되는 Treiber 스택을 보여준다. (L6-11,16-24) 푸시 및 팝 작업은 Guard로 구분되며, (L8,10,17,21) 포인터 판독 작업은 Guard를 참조하고, (L14) 실드가 생성되며, (L19) 실드는 스레드의 보호된 포인터 리스트에 로컬 포인터 커서를 기록하여 보호하려고 하며, 실패하면 처음부터 다시 시도한다. (L20,25) 보호 후 로컬 포인터는 실드를 통해 역참조며, (L26) 팝업을 시도한 후에는 보호되지 않는다. (L19) 로컬 포인터는 활성 상태 내에서 보호되어야 하지만 (L25) 해당 실드는 활성 상태 외부에서 안전하게 역참조될 수 있다는 점에 유의할 필요가 있다.
5. 알고리즘
이 섹션에서는 EBR의 시대 컨센서스(
Figure pat00031
5.1)를 일반화하는 해저드-시대 컨센서스에 초점을 맞추어 PEBR의 알고리즘을 설명한다. PEBR의 알고리즘은 Snowflake에서 영감을 얻어, hazad-시대 컨센서스, 보호 및 이젝션도 채택하고 있다. 본 개시는 Snowflake에서 어떤 디자인이 채택되었는지 그리고 어떤 것이 본 개시 자신의 것인지 분명히 설명할 것이다.
5.1. 해저드-시대 컨센서스
PEBR의 해저드-시대 컨센서스는 보호되는 포인터를 고려하기 위한 EBR의 시대 컨센서스의 개선이다. 예를 들어, 도 4에 제시된 해저드-시대 컨센서스 사건 그래프를 참조하라. EBR에서와 마찬가지로 각 A(e)에 대해 (i) G(e)는 B(e)보다 먼저 발생하며, (ii) E(e)는 G(e + 2)보다 먼저 발생하도록 강제된다. HP에서와 마찬가지로,
Figure pat00032
3.2에서 논의한 바와 같이 각각 생성되는 것과 동일한 활성 상태 내에서 보호되는 보호 로컬 포인터의 집합은 다른 스레드가 게시된 포인터의 수집을 억제하도록 추적하여 간행된다. Snowflake에서와 마찬가지로 블록은 (i) e -3 또는 그 이전에 고정된 활성 상태로 폐기된 경우, 그리고 (ii) 현재 어떤 스레드에 의해 보호되는 것으로 게시되지 않은 경우 e에 고정된 활성 상태에서 수집될 수 있다.
PEBR의 컨센서스는 EBR 및 Snowflake의 컨센서스와 유사하게 use-after-free 오류를 방지한다. 도 3에 설명된 EBR의 시대 컨센서스와 주목할 만한 차이점은 상자 안에 있다. 이전과 같이(빨간색) 2(또는 그 이후)에 고정된 활성 상태 내에서 b에 대한 로컬 포인터를 만들고 보호할 수 없다. (E(1)) b가 보호되고 있다는 사실은 b를 통해 E(1), G(3) 및 B(3)를 통하여 보호를 인정받아 A(1) (¬F(b), 녹색)의 끝에 게시되며, b는 collect에서 수집되지 않는다. (D(b),
Figure pat00033
, 갈색) 블록 b는 활성 상태 내에 있는지 여부에 관계 없이 보호된 후 및 비보호 전에 역참조될 수 있다. (E(8)) b가 더 이상 보호되지 않는다는 사실은 A(8)의 끝에 게시된다. 마지막으로 (F(b), 파란색) b의 모든 역참조는
Figure pat00034
, E(8), G(10), B(10), F(b) 이전에 발생하며 use-after-free 오류를 방지한다. 도 4에서 보듯이 PEBR의 해저드-시대 컨센서스는 Snowflake의 컨센서스와 유사하지만, (i) PEBR에서 발생 전 관계를 통해 이전된 소유권이 포인터 앨리어싱 및 공유(
Figure pat00035
3.2)를 지원하기에 더 복잡하며, 더 중요한 것은 (ii) 컨센서스는 비차단 이젝션 성격도 고려해야 한다.이 섹션의 나머지 부분에서는 비차단 이젝션과 시대(
Figure pat00036
5.2) 및 로컬 포인터 보호(
Figure pat00037
5.3)를 동기화하는 방법을 설명한다. 그런 다음 비차단 이젝션 알고리즘 자체에 대해 설명한다(
Figure pat00038
5.4).
5.2. 시대의 동기화
해저드-시대 컨센서스(consensus)는 각 A(e)에 대해 (i) G(e)가 B(e)보다 먼저 일어나고 (ii) E(e)가 G(e + 2)보다 먼저 발생한다고 가정한다. 이를 시행하기 위해 다음과 같이 활성 상태와 글로벌 시대를 구현하고 동기화한다.
G는 글로벌 시대를 포함하는 공유 변수, Li는 i번째 스레드의 로컬 시대를 포함하는 공유 변수라 하자. A(e)라 하는 활성 상태를 생성하려면, 본 개시는 (B1) 글로벌 시대에서 e 값을 읽고, (B2) 로컬 시대로 기록하며, (B3) RAW 동기화 펜스를 발행하고, (B4) 글로벌 시대가 여전히 e인지 여부를 확인하고, 그렇지 않으면 처음부터 다시 시도한다. 스레드가 비동기적으로 중간에 이젝트되지 않도록 하려면 마지막 단계가 필요하다. 활성 상태를 파괴하기 위해 본 개시는 (E1) 로컬 시대로 센티넬 값을 쓴다. 글로벌 시대를 진전시키기 위해, 본 개시는 (A1) 글로벌 시대의 e 값을 읽고, (A2) RAR 동기화(읽기-후-읽기) 펜스를 발행하고, (A3) 각 스레드의 로컬 시대가 e인지, 센티넬인지 확인하고, (A4) 그 경우에 한해서만 글로벌 시대는 CAS를 통해 e+1로 진전시킨다.
G(e)는, A4가 해제/수집 동기화를 통해 B1보다 먼저 발생하기 때문에, B(e)보다 먼저 발생하게 된다. 반면, E(e)는 다음과 같은 이유로 G(e + 2)보다 먼저 발생한다. B4는 A1보다 G에서 더 오래된 값을 읽기 때문에 B3은 A2보다 먼저 일어난다. 따라서 Li에 대한 B2의 쓰기는 A3의 읽기에서 볼 수 있다. 그런 다음 A4로 진행하기 위해 Li에 대한 E(e)의 쓰기 또는 이후 쓰기를 A3에서 읽으며, 해제/수집 동기화에 의해 E(e)가 G(e + 2) 이전에 일어난다.
5.3. 로컬 포인터 보호의 동기화
본 개시는 보호 포인터 리스트를 게시할 때 오직 활성 상태의 끝에만 Snowflake를 따른다. 도 4(녹색)에서 설명된 바와 같이 보호는 둘러싸는 활성 상태의 끝에서만 인식될 필요가 있기 때문에 안전하다. 특히 로컬 포인터가 활성 상태 내에서 완전히 보호되는 경우 보호가 전혀 게시되지 않는다. 결과적으로, 비보호성은 후기 활성 상태가 끝날 때까지 수집에는 즉시 영향을 미치지 않을 수 있다. 예를 들어, 도 4의 P(b)는 활성 상태 외부에서 발생하며, 그 효과는 E(8)에서만 발표된다.
또한 블룸 필터를 사용하여 보호 포인터 리스트를 대략적으로 압축하는 Snowflake를 따라가 리스트 위에 반복 횟수를 줄인다. 활성 상태(예: E(1))의 끝에서 해당 스레드의 보호 포인터 리스트는 블룸 필터로 근사치를 산출한 다음 해당 로컬 시대와 함께 게시되며, 글로벌 시대가 진전되면(예: G(3) 모든 스레드에 의해 발행된 블룸 필터를 수집하여 결합에 의해 단일 블룸 필터로 병합한 후 발행된다. 글로벌 시대와 더불어 이후 글로벌 블룸 필터는 활성 상태(예: E(3))의 시작 부분에서 검색되며, collect에서 보호 블록(예: ¬F(b))의 수집 방지를 위해 사용된다. 부수적인 이점으로서, 각 스레드의 보호된 포인터 리스트는 대부분 스레드 로컬이 되기 때문에 캐시 인접성이 개선된다(아래 설명과 같이 이젝트될 경우에만 다른 스레드에 의해 액세스됨).
과한 근사치 추정은 단지 폐기한 블록의 수집을 방해하는 것이기 때문에 안전하다. PEBR을 엄격하게 견고하게 렌더링하지 않지만 보호 포인터가 총 128개 있고 블룸 필터가 해시 8개로 128바이트인 경우 평균적으로 비보호 은퇴 블록의 2.55%만이 재확보되지 않는다는 점에서 확률적으로 견고하다. 구현 시 128비트 MurmurHash3 결과의 그 크기의 블룸 필터와 각 더블바이트 청크를 해시로 사용한다.
견고성을 위해 본 개시는 시대와 블룸 필터를 차단하지 않는 방식으로 동기화한다. 본 개시의 아이디어는 본 개시가 CAS를 수행할 수 있도록 블룸 필터와 시대에 포인터를 싱글(single)-워드(word)의 상태로 두는 것이다. 128바이트 블룸 필터에 대한 포인터는 태깅당 7비트를 허용하고, 시대에는 3비트(5 시대 이상을 구분할 필요가 없으므로, 폐기 블록의 경우 3개, 시대 skew의 경우 2개), 핀에는 1비트(스레드가 활성 상태 안에 있는지 여부 확인)만 있으면 되기 때문에 상태가 워드에 맞는다. 그 결과 CAS를 실시함으로써 로컬 및 글로벌 시대의 시대 번호와 블룸 필터를 동시에 발행할 수 있다. 상태 워드는 또한 아래 설명에 따라 이젝션을 가지는 동기화에 결정적으로 사용될 것이다.
5.4. 비차단 이젝션
본 개시는 견고함을 보장하기 위해, Snowflake를 따라 비협조적 스레드(즉, 무의식적으로 그들의 활동 상태를 파괴하는 것)를 이젝트한다. 자기 충족성이 없거나(페이지 결함 핸들러에 대한 의존성 때문에) 엄밀한 의미에서 견고하지 않은(잠금기 사용으로 인해) Snowflake의 이젝션 알고리즘과 달리, PEBR 이젝션 알고리즘은 다음과 같이 비차단적인 방식으로 해저드-시대 컨센서스와 동기화하여 자기 충족성이 있고 견고하다.
이젝트하는(ejecting) 스레드와 이젝트되는(ejected) 스레드는 꺼낸 스레드의 상태 워드에서 서로 동기화된다. 그렇게 하기 위해, 상태 워드의 나머지 비트에, 본 개시는 스레드가 이젝트되는지 여부를 나타내는 플래그를 추가로 저장한다. Epoch, Pin 및 Eject를 상태의 해당 태그라 하자. 이젝트하는 스레드(A로 지칭됨)은 이젝트되는 스레드(B로 지칭됨)의 상태 워드를 다음과 같이 변경한다.
A1. B의 상태에 대해 CAS를 수행하여 B의 Eject를 표시한다.
A2. B의 보호된 포인터 리스트를 읽고 블룸 필터로 대략적인 값을 구한다.
A3. 근사 블룸 필터, 임의 Epoch, 표시되지 않은 Pin, Eject로 표시된 CAS를 수행하여 B의 상태를 새 상태로 업데이트한다.
A1의 목적은 B에게 이젝트할 의도를 가지고 통지하는 것이며, A2와 A3의 목적은 B가 이젝트될 때 B의 보호 포인터가 발행되도록 하는 것이다. 이 과정에는 잠금이 없다. 특히 C라고 하는 다른 스레드가 B를 동시에 이젝트할 수도 있고, C가 A1의 CAS에서 실패하더라도 B가 이젝트되고 있다는 사실을 인식하고 A2와 A3을 실행함으로써 A가 B를 이젝트하는 것을 돕는다.
이젝트될 때 스레드 B에 이젝션 통지를 하고 다음과 같이 보호, 폐기 및 수집 작업에서 이를 품위 있게 처리한다.
보호와 동기화: 함수 보호가 지정된 로컬 포인터를 보호된 포인터 리스트에 추가한 다음 스레드가 배출되지 않은 경우 유효함을
Figure pat00039
3.2로부터 상기해야 한다. 구체적으로 검증은 다음과 같이 상태 워드와 상호 작용한다.
B1. 로컬 포인터를 보호된 포인터 리스트에 쓴다.
B2. 그것의 상태 워드를 읽는다.
B3. Eject 비트가 표시되면 스레드가 이젝트되므로 보호 작업은 실패한다.
이젝션은 다음과 같은 상태 워드를 통해 보호와 동기화된다. A를 이젝트하는 스레드라 하고 B를 로컬 포인터를 보호하려는 이젝트되는 스레드 B라 하자. 집행 순서에 따라 A1은 B2보다 먼저 발생하거나 B1은 A1보다 먼저 발생한다. 전자의 경우, B2는 Eject가 표시된 상태에서 상태 워드를 읽어야 하며, B3는 지정된 로컬 포인터를 보호하지 못한다. 후자의 경우, A2는 B1로 쓰여진 로컬 포인터를 읽어야 하며, A3는 그 보호장치를 블룸 필터로 게시해야 한다. 두 경우 모두 B에서 성공적으로 보호되는 로컬 포인터는 B가 이젝트되는지 여부와 상관없이 항상 활성 상태의 끝에 블룸 필터에 게시된다.
HP에서와 마찬가지로, 위의 사례 분석은 본 개시가 RAW-동기화 펜스를 발행하여 A1의 쓰기(및 B1)와 A2의 읽기(및 B2의 읽기, 각각) 사이의 순서를 강제할 때만 견고하다. RAW 동기화 펜스를 발행하여 동기화 비용을 줄이기 위해, 핫 경로에 컴파일러 펜스(이진수로 나타나지 않음)만 사용하기 위해 Dice를 따르는데, 이는 본 개시의 경우 B이다. 콜드 경로에서 프로세스 전체 메모리 펜스 동기화 비용을 더 많이 부담하는 경우는 A이다.
폐기 및 수거와 동기화: 해저드 시대 컨센서스는 폐기 및 수거를 활성상태로 불러야 하므로, 높은 수준의 API(
Figure pat00040
4.2)를 Guard에 참조한다. 그러나 Guard에 대한 참조가 있더라도 해당 스레드가 이젝트되어 활성 상태가 아닐 수 있다. 이 함수들은 이젝트된 경우에도 진행하기 위해 다음과 같이 이젝션과 동기화된다. 이들은 먼저 스레드의 상태 워드를 읽고, 스레드의 Eject 비트가 표시되지 않으면 로컬 시대를 사용하고, 그렇지 않으면 폴백(fallback)으로 글로벌 시대를 읽고 사용한다. 글로벌 시대는 이러한 함수들이 단지 특정 글로벌 시대에 도달(즉, 일부 e의 경우, G(e)가 이전에 발생)했다는 사실만 인식하면 되기 때문에 사용하기에 안전하다. 결과적으로 이러한 함수는 스레드를 이젝트해도 항상 성공한다.
6. 속성
PEBR은 안전하다. 요구사항이 충족될 경우 PEBR의 해저드-시대 컨센서스의 안전성을 입증한다.
정리 6.1 (안전). 요건 3.1 ~ 3.4가 충족되면 PEBR에서 관리하는 메모리 블록에 대해 use-after-free 오류가 발생하지 않는다.
증명. b를 PEBR에 의해 관리되는 메모리 블록으로 하고, 그것의 retirement R(b)가 시대 e에 고정된 활성 상태 내에서 발생한다고 가정한다. b의 보호가 G(e + 3), G(e + 4), ····· G(f - 1)의 관점에서 공표되지만 G(f )의 관점에서 공표되지 않는다고 가정하면, 수집 F(b)는 f 이후에 고정된 활성 상태 내에서 발생할 수 있다.
각 역참조 D(b)에서 b까지 고려한다. 가정으로 D(b)는 활성 상태 내에서 보호되며, a라고 말한다. 본 개시는 a가 e+1 또는 그 이전에 고정되어야 한다는 것을 증명한다. 그렇지 않다고 가정하면, a는 e + 2 이후에 고정된다. 요건 3.1과 3.2에 의해 b에 대한 로컬 포인터 l이 위치로부터의 읽기 이벤트가 되도록 한다. w는 r이 읽히는 쓰기 이벤트가 되도록 한다. b′ = blk(l)로 한다. 그러면 본 개시는 다음을 얻는다.
Figure pat00041
여기서
Figure pat00042
는 발생 전 관계를 나타낸다. r은 w에서 읽기 때문에 w는 r에 보이고 따라서 R(b)에 보인다. 요건 3.3 (ii)에 의해 R(b)보다 먼저 R(b')이 발생한다. 요건 3.4에 의해 b′는 b가 되기 전에 a 안에서 보호되어야 한다. 따라서 반복적으로 b′′, b′′′,···에 대한 무한 수의 로컬 포인터를 b 이전의 내부에 생성하여 보호해야 하며, 실행의 정밀성과 모순된다. 대조적으로, a는 e + 1 또는 그 이전에 고정되어야 한다.나머지 증명은 대체로 Snowflake의 증명과 같다. 보호는 G(f)의 관점에서 공표되지 않기 때문에 b의 보호는 결국 해제된다. 특히, 그러한 보호되지 않는 사건은 f - 2 또는 그 이전에 고정된 a'라 불리는 스레드 활성 상태가 끝나기 전에 발생한다. P(b)를 그러한 해제 사건이라 하자. 그 후 D(b)는 P(b), a′의 끝, G(f) 및 F(b)보다 먼저 발생하여 use-after-free 오류를 방지한다.
또한 PEBR의 안전성은 가혹한 파라미터(예: 모든 8개 활성 상태의 다른 스레드 이젝트하는)와 LLVM AddressSanitizer를 사용하여 시험한다.
PEBR은 견고하다. 비협조적 스레드가 이젝트되어 시대 진전과 블록 수집을 보장한다. 그 결과, 본 개시의 실험(
Figure pat00043
7)에서 비협조적 스레드가 존재하더라도 메모리 사용량은 거의 그대로 유지된다.
PEBR은 빠르다. 구체적으로는 값비싼 RAW동기화 펜스를 발행하지도 않고, 각 역참조에 대한 메모리 간접화를 유발하지도 않는다. 보호되는 로컬 포인터를 추적하면 런타임 오버헤드가 발생하지만, 본 개시의 실험(ð7)에서 EBR에 비해 15% 미만이다.
PEBR은 컴팩트다. 글로벌 및 스레드별 메타데이터만 필요하며, 참조 카운터 또는 시대와 같은 경우 블록당 공간 오버헤드가 발생하지 않는다.
PEBR은 자기 충족한다. 표준 C18/C++17 완화된 메모리 동시성과 프로세스 전반의 메모리 펜스로 효율적으로 구현할 수 있으며, 그 중 후자는 Linux와 Windows의 사용자 공간 프로그램에 널리 이용 가능하며, C/C++에서 표준화되고 있다. 본 개시는 Linux 및 Windows에서 PEBR을 구현하고 테스트했다. 더욱이, 인터럽트 핸들러를 설치하는 등, 실행 환경을 방해하여 영향을 미치지 않는다.
PEBR은 광범위하게 적용된다.
Figure pat00044
3.4에서 논의한 바와 같이, PEBR은 HP보다, 적어도 Harris의 리스트과 Harris-Herlihy-Shavit의 리스트에 대해서, 그리고 적어도 EBR과 같이 적용 가능한 경우, Snowflake보다 더 적용 가능하다. 또한 포인터 앨리어싱, 포인터 태그 지정, RMW 연산 등 동시 프로그래밍에 널리 사용되는 포인터 연산을 허용한다. 또한 정적으로 알 수 없는 수의 보호된 포인터를 지원하며, 예를 들어, Bonsai 트리에 기본적으로 사용된다.
도 6은 다양한 실시예들에 따른 컴퓨터 시스템(600)을 도시하는 도면이다.
도 6을 참조하면, 다양한 실시예들에 따른 컴퓨터 시스템(600)은 인터페이스 모듈(610), 메모리(620), 또는 프로세서(630) 중 적어도 하나를 포함할 수 있다. 어떤 실시예들에서, 컴퓨터 시스템(600)의 구성 요소들 중 적어도 어느 하나가 생략될 수 있으며, 적어도 하나의 다른 구성 요소가 추가될 수 있다. 어떤 실시예들에서, 컴퓨터 시스템(600)의 구성 요소들 중 적어도 어느 두 개가 하나의 통합된 회로로 구현될 수 있다.
인터페이스 모듈(610)은 컴퓨터 시스템(600)을 위한 인터페이스를 제공할 수 있다. 일 실시예에 따르면, 인터페이스 모듈(610)은 통신 모듈을 포함하며, 통신 모듈은 외부 장치와 통신을 수행할 수 있다. 통신 모듈은 컴퓨터 시스템(600)과 외부 장치 간 통신 채널을 수립하고, 통신 채널을 통해 외부 장치와 통신을 수행할 수 있다. 통신 모듈은 유선 통신 모듈 또는 무선 통신 모듈 중 적어도 하나를 포함할 수 있다. 유선 통신 모듈은 외부 장치와 유선으로 연결되어, 유선으로 통신할 수 있다. 무선 통신 모듈은 근거리 통신 모듈 또는 원거리 통신 모듈 중 적어도 어느 하나를 포함할 수 있다. 근거리 통신 모듈은 외부 장치와 근거리 통신 방식으로 통신할 수 있다. 원거리 통신 모듈은 외부 장치와 원거리 통신 방식으로 통신할 수 있다. 여기서, 원거리 통신 모듈은 무선 네트워크를 통해 외부 장치와 통신할 수 있다. 다른 실시예에 따르면, 인터페이스 모듈(610)은 입력 모듈 또는 출력 모듈 중 적어도 하나를 포함할 수 있다. 입력 모듈은 컴퓨터 시스템(600)의 적어도 하나의 구성 요소에 사용될 신호를 입력할 수 있다. 입력 모듈은, 사용자가 컴퓨터 시스템(600)에 직접적으로 신호를 입력하도록 구성되는 입력 장치, 주변 환경을 감지하여 신호를 발생하도록 구성되는 센서 장치, 또는 영상을 촬영하여, 영상 데이터를 생성하도록 구성되는 카메라 모듈 중 적어도 어느 하나를 포함할 수 있다. 출력 모듈은 정보를 시각적으로 표시하기 위한 표시 모듈 또는 정보를 오디오 신호로 출력하기 위한 오디오 모듈 중 적어도 하나를 포함할 수 있다.
메모리(620)는 컴퓨터 시스템(600)의 적어도 하나의 구성 요소에 의해 사용되는 다양한 데이터를 저장할 수 있다. 예를 들면, 메모리(620)는 휘발성 메모리 또는 비휘발성 메모리 중 적어도 어느 하나를 포함할 수 있다. 데이터는 적어도 하나의 프로그램 및 이와 관련된 입력 데이터 또는 출력 데이터를 포함할 수 있다. 프로그램은 메모리(620)에 적어도 하나의 명령을 포함하는 소프트웨어로서 저장될 수 있다.
프로세서(630)는 메모리(620)의 프로그램을 실행하여, 컴퓨터 시스템(600)의 적어도 하나의 구성 요소를 제어할 수 있다. 이를 통해, 프로세서(630)는 데이터 처리 또는 연산을 수행할 수 있다. 이 때, 프로세서(630)는 메모리(620)에 저장된 명령을 실행할 수 있다.
프로세서(630)는 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현할 수 있다. 이 때 프로세서(630)는, 포인터 기반 메모리 수집 기법의 함수들과 포인터 기반 메모리 수집 기법의 함수들과 함께, 시대 기반 메모리 수집 기법의 함수들을 혼합하고, 이를 통해 포인터 및 시대 기반 메모리 수집 기법이 구현될 수 있다. 그리고, 프로세서(630)는, 상술된 요건 3.1 및 3.2를 충족하도록, 포인터 및 시대 기반 메모리 수집 기법을 구현할 수 있다. 또한, 프로세서(630)는, 이젝션 알고리즘을 기반으로, 포인터 및 시대 기반 메모리 수집 기법을 구현할 수 있다. 이에 따라, 프로세서(630)는 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행할 수 있다.
도 7은 다양한 실시예들에 따른 컴퓨터 시스템(600)의 방법을 도시하는 도면이다.
도 7을 참조하면, 컴퓨터 시스템(600)는 710 단계에서 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현할 수 있다. 프로세서(630)는, 포인터 기반 메모리 수집 기법의 함수들과 포인터 기반 메모리 수집 기법의 함수들과 함께, 시대 기반 메모리 수집 기법의 함수들을 혼합하고, 이를 통해 포인터 및 시대 기반 메모리 수집 기법이 구현될 수 있다.
포인터 기반 메모리 수집 기법의 함수들은, 공유 메모리에 지정된 로컬 포인터(I)가 스레드에 의해 보호되도록, 보호된 포인터 리스트에 로컬 포인터(I)를 추가하기 위한 protect(I), 보호된 포인터 리스트에 있는 로컬 포인터(I)를 제거하기 위한 unprotect(I), 보호된 포인터에 있는 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는 보호된 포인터 리스트에 없는 로컬 포인터에 대한 수집을 위한 collect() 중 적어도 하나를 포함할 수 있다. 시대 기반 메모리 수집 기법의 함수들은, 스레드가 활성 상태에서 공유 메모리에 액세스하도록 설정하기 위한 set_active(), 스레드가 비활성 상태에서 공유 메모리에 액세스하기 않도록 설정하기 위한 set_quiescent(), 활성 상태에 있는 스레드에 대해 생성된 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는 활성 상태에 있는 스레드에 대해 폐기된 로컬 포인터에 대한 수집을 위한 collect() 중 적어도 하나를 포함할 수 있다. 이를 통해, 포인터 및 시대 기반 메모리 수집 기법은, set_active(), set_quiescent(), protect(I), unprotect(I), retire(I), 또는 collect() 중 적어도 두 개로 구현될 수 있다.
프로세서(630)는, 상술된 요건 3.1 및 3.2를 충족하도록, 포인터 및 시대 기반 메모리 수집 기법을 구현할 수 있다. 요건 3.1은, protect(l)가 참(true)일 때, 스레드가 활성 상태에서 공유 메모리를 읽음으로써, 로컬 포인터(I)가 동일한 활성 상태에서 생성되는 보호 요건을 나타낼 수 있다. 요건 3.2는, 포인터 및 시대 기반 메모리 수집 기법은, protect(l)가 참일 때, unprotect(l)는 생성된 로컬 포인터(l)의 보호와 역참조 사이에 호출되지 않는 역참조 요건을 나타낼 수 있다.
프로세서(630)는, 이젝션 알고리즘을 기반으로, 포인터 및 시대 기반 메모리 수집 기법을 구현할 수 있다. 프로세서(630)는, 이젝트하는 스레드와 이젝트되는 스레드를 이젝트되는 스레드의 상태 워드에서 서로 동기화할 수 있다. 그리고, 이젝트하는 스레드가 이젝트되는 스레드의 상태 워드를 변경하도록 구성될 수 있다. 구체적으로, 프로세서(630)는 이젝트되는 스레드의 상태를 기반으로, 상태 워드의 나머지 비트들에 이젝트되는 스레드가 이젝트됨을 나타내는 플래그를 표시할 수 있다. 이 후, 프로세서(630)는 이젝트되는 스레드의 보호된 포인터 리스트를 기반으로, 이젝트되는 스레드의 상태를 업데이트하도록 구성될 수 있다.
이에 따라, 컴퓨터 시스템(600)은 720 단계에서 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행할 수 있다. 컴퓨터 시스템600)은, 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법이 혼합된 포인터 및 시대 기반 메모리 수집 기법을 이용하여, 메모리 사용량이 적고, 빠르고, 많은 자료구조에 적용할 수 있고, 메모리를 빠짐없이 수집할 수 있다. 포인터 및 시대 기반 메모리 수집 기법을 적용함으로써, 시스템 및 고성능 소프트웨어의 메모리 사용량을 줄이고, 지연속도(latency)를 낮추고, 처리율(throughput)을 높이는 최적화를 수행할 수 있다.
포인터 및 시대 기반 메모리 수집 기법은 동시성 자료를 필요로하는 대부분의 시스템 소프트웨어 및 고성능 소프트웨어에 적용될 수 있다. 가령 운영체제 내에서 여러 스레드가 빈번하게 동시에 접근하는 자료구조, 가령 페이지 테이블, 스케쥴링 테이블, b-tree 등에 적용될 수 있고, 데이터베이스 관리 시스템에서 타입스탬프 생성기, 동시성 컨트롤, 해시 테이블 등에 적용될 수 있고, 네트워킹 시스템에서 DNS 테이블, 패킷 오프로딩 등에 적용될 수 있다. 모든 시스템 및 고성능 소프트웨어는 코너 케이스에서도 잘 동작해야 하므로, 수집 기법으로써 필요로 하는 특질을 모두 갖춘 포인터 및 시대 기반 메모리 수집 기법이 요긴하게 사용될 수 있을 것이다. 이를 통해, 포인터 및 시대 기반 메모리 수집 기법을 시스템 및 고성능 소프트웨어에 적용하면 큰 성능 이득을 볼 수 있을 것으로 기대한다. 그러므로 거대한 클라우드를 운용하는 기업의 경우 막대한 비용 절감을 이룰 수 있을 것으로 기대한다.
다양한 실시예들에 따른 컴퓨터 시스템(600)의 방법은, 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계, 및 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행하는 단계를 포함할 수 있다.
다양한 실시예들에 따르면, 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계는, 포인터 기반 메모리 수집 기법의 함수들을 이용하여, 포인터 및 시대 기반 메모리 수집 기법을 구현할 수 있다.
다양한 실시예들에 따르면, 포인터 기반 메모리 수집 기법의 함수들은, 공유 메모리에 지정된 로컬 포인터(I)가 스레드에 의해 보호되도록, 보호된 포인터 리스트에 로컬 포인터(I)를 추가하기 위한 protect(I), 보호된 포인터 리스트에 있는 로컬 포인터(I)를 제거하기 위한 unprotect(I), 보호된 포인터에 있는 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는 보호된 포인터 리스트에 없는 로컬 포인터에 대한 수집을 위한 collect() 중 적어도 하나를 포함할 수 있다.
다양한 실시예들에 따르면, 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계는, 포인터 기반 메모리 수집 기법의 함수들과 함께, 시대 기반 메모리 수집 기법의 함수들을 이용하여, 포인터 및 시대 기반 메모리 수집 기법을 구현할 수 있다.
다양한 실시예들에 따르면, 시대 기반 메모리 수집 기법의 함수들은, 스레드가 활성 상태에서 공유 메모리에 액세스하도록 설정하기 위한 set_active(), 스레드가 비활성 상태에서 공유 메모리에 액세스하기 않도록 설정하기 위한 set_quiescent(), 활성 상태에 있는 스레드에 대해 생성된 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는 활성 상태에 있는 스레드에 대해 폐기된 로컬 포인터에 대한 수집을 위한 collect() 중 적어도 하나를 포함할 수 있다.
다양한 실시예들에 따르면, 포인터 및 시대 기반 메모리 수집 기법은, protect(l)가 참(true)일 때, 스레드가 활성 상태에서 공유 메모리를 읽음으로써, 로컬 포인터(I)가 동일한 활성 상태에서 생성되는 보호 요건을 충족할 수 있다.
다양한 실시예들에 따르면, 포인터 및 시대 기반 메모리 수집 기법은, protect(l)가 참일 때, unprotect(l)는 생성된 로컬 포인터(l)의 보호와 역참조 사이에 호출되지 않는 역참조 요건을 충족할 수 있다.
다양한 실시예들에 따르면, 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계는, 이젝트하는 스레드와 이젝트되는 스레드를 이젝트되는 스레드의 상태 워드에서 서로 동기화하는 단계, 및 이젝트하는 스레드가 이젝트되는 스레드의 상태 워드를 변경하는 단계를 포함할 수 있다.
다양한 실시예들에 따르면, 상태 워드를 변경하는 단계는, 이젝트되는 스레드의 상태를 기반으로, 상태 워드의 나머지 비트들에 이젝트되는 스레드가 이젝트됨을 나타내는 플래그를 표시하는 단계, 및 이젝트되는 스레드의 보호된 포인터 리스트를 기반으로, 이젝트되는 스레드의 상태를 업데이트하는 단계를 포함할 수 있다.
다양한 실시예들에 따른 컴퓨터 시스템(600)은, 메모리(620), 및 메모리(620)와 연결되고, 메모리(620)에 저장된 적어도 하나의 명령을 실행하도록 구성된 프로세서(630)를 포함할 수 있다.
다양한 실시예들에 따르면, 프로세서(630)는, 포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현하고, 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행하도록 구성될 수 있다.
다양한 실시예들에 따르면, 프로세서(630)는, 포인터 기반 메모리 수집 기법의 함수들을 이용하여, 포인터 및 시대 기반 메모리 수집 기법을 구현할 수 있다.
다양한 실시예들에 따르면, 포인터 기반 메모리 수집 기법의 함수들은, 공유 메모리에 지정된 로컬 포인터(I)가 스레드에 의해 보호되도록, 보호된 포인터 리스트에 로컬 포인터(I)를 추가하기 위한 protect(I), 보호된 포인터 리스트에 있는 로컬 포인터(I)를 제거하기 위한 unprotect(I), 보호된 포인터에 있는 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는 보호된 포인터 리스트에 없는 로컬 포인터에 대한 수집을 위한 collect() 중 적어도 하나를 포함할 수 있다.
다양한 실시예들에 따르면, 프로세서(630)는, 포인터 기반 메모리 수집 기법의 함수들과 함께, 시대 기반 메모리 수집 기법의 함수들을 이용하여, 포인터 및 시대 기반 메모리 수집 기법을 구현할 수 있다.
다양한 실시예들에 따르면, 시대 기반 메모리 수집 기법의 함수들은, 스레드가 활성 상태에서 공유 메모리에 액세스하도록 설정하기 위한 set_active(), 스레드가 비활성 상태에서 공유 메모리에 액세스하기 않도록 설정하기 위한 set_quiescent(), 활성 상태에 있는 스레드에 대해 생성된 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는 활성 상태에 있는 스레드에 대해 폐기된 로컬 포인터에 대한 수집을 위한 collect() 중 적어도 하나를 포함할 수 있다.
다양한 실시예들에 따르면, 포인터 및 시대 기반 메모리 수집 기법은, protect(l)가 참(true)일 때, 스레드가 활성 상태에서 공유 메모리를 읽음으로써, 로컬 포인터(I)가 동일한 활성 상태에서 생성되는 보호 요건을 충족할 수 있다.
다양한 실시예들에 따르면, 포인터 및 시대 기반 메모리 수집 기법은, protect(l)가 참일 때, unprotect(l)는 생성된 로컬 포인터(l)의 보호와 역참조 사이에 호출되지 않는 역참조 요건을 충족할 수 있다.
다양한 실시예들에 따르면, 프로세서(630)는, 이젝트하는 스레드와 이젝트되는 스레드를 이젝트되는 스레드의 상태 워드에서 서로 동기화하고, 이젝트하는 스레드가 이젝트되는 스레드의 상태 워드를 변경하도록 구성될 수 있다.
다양한 실시예들에 따르면, 프로세서(630)는, 이젝트되는 스레드의 상태를 기반으로, 상태 워드의 나머지 비트들에 이젝트되는 스레드가 이젝트됨을 나타내는 플래그를 표시하고, 이젝트되는 스레드의 보호된 포인터 리스트를 기반으로, 이젝트되는 스레드의 상태를 업데이트하도록 구성될 수 있다.
이상에서 설명된 장치는 하드웨어 구성 요소, 소프트웨어 구성 요소, 및/또는 하드웨어 구성 요소 및 소프트웨어 구성 요소의 조합으로 구현될 수 있다. 예를 들어, 실시예들에서 설명된 장치 및 구성 요소는, 프로세서, 콘트롤러, ALU(arithmetic logic unit), 디지털 신호 프로세서(digital signal processor), 마이크로컴퓨터, FPGA(field programmable gate array), PLU(programmable logic unit), 마이크로프로세서, 또는 명령(instruction)을 실행하고 응답할 수 있는 다른 어떠한 장치와 같이, 하나 이상의 범용 컴퓨터 또는 특수 목적 컴퓨터를 이용하여 구현될 수 있다. 처리 장치는 운영 체제(OS) 및 상기 운영 체제 상에서 수행되는 하나 이상의 소프트웨어 어플리케이션을 수행할 수 있다. 또한, 처리 장치는 소프트웨어의 실행에 응답하여, 데이터를 접근, 저장, 조작, 처리 및 생성할 수도 있다. 이해의 편의를 위하여, 처리 장치는 하나가 사용되는 것으로 설명된 경우도 있지만, 해당 기술분야에서 통상의 지식을 가진 자는, 처리 장치가 복수 개의 처리 요소(processing element) 및/또는 복수 유형의 처리 요소를 포함할 수 있음을 알 수 있다. 예를 들어, 처리 장치는 복수 개의 프로세서 또는 하나의 프로세서 및 하나의 콘트롤러를 포함할 수 있다. 또한, 병렬 프로세서(parallel processor)와 같은, 다른 처리 구성(processing configuration)도 가능하다.
소프트웨어는 컴퓨터 프로그램(computer program), 코드(code), 명령(instruction), 또는 이들 중 하나 이상의 조합을 포함할 수 있으며, 원하는 대로 동작하도록 처리 장치를 구성하거나 독립적으로 또는 결합적으로(collectively) 처리 장치를 명령할 수 있다. 소프트웨어 및/또는 데이터는, 처리 장치에 의하여 해석되거나 처리 장치에 명령 또는 데이터를 제공하기 위하여, 어떤 유형의 기계, 구성 요소(component), 물리적 장치, 컴퓨터 저장 매체 또는 장치에 구체화(embody)될 수 있다. 소프트웨어는 네트워크로 연결된 컴퓨터 시스템 상에 분산되어서, 분산된 방법으로 저장되거나 실행될 수도 있다. 소프트웨어 및 데이터는 하나 이상의 컴퓨터 판독 가능 기록 매체에 저장될 수 있다.
다양한 실시예들에 따른 방법은 다양한 컴퓨터 수단을 통하여 수행될 수 있는 프로그램 명령 형태로 구현되어 컴퓨터-판독 가능 매체에 기록될 수 있다. 이 때, 매체는 컴퓨터로 실행 가능한 프로그램을 계속 저장하거나, 실행 또는 다운로드를 위해 임시 저장하는 것일 수도 있다. 그리고, 매체는 단일 또는 수 개의 하드웨어가 결합된 형태의 다양한 기록수단 또는 저장수단일 수 있는데, 어떤 컴퓨터 시스템에 직접 접속되는 매체에 한정되지 않고, 네트워크 상에 분산 존재하는 것일 수도 있다. 매체의 예시로는, 하드 디스크, 플로피 디스크 및 자기 테이프와 같은 자기 매체, CD-ROM 및 DVD와 같은 광기록 매체, 플롭티컬 디스크(floptical disk)와 같은 자기-광 매체(magneto-optical medium), 및 ROM, RAM, 플래시 메모리 등을 포함하여 프로그램 명령어가 저장되도록 구성된 것이 있을 수 있다. 또한, 다른 매체의 예시로, 어플리케이션을 유통하는 앱 스토어나 기타 다양한 소프트웨어를 공급 내지 유통하는 사이트, 서버 등에서 관리하는 기록매체 내지 저장매체도 들 수 있다.
본 문서의 다양한 실시예들 및 이에 사용된 용어들은 본 문서에 기재된 기술을 특정한 실시 형태에 대해 한정하려는 것이 아니며, 해당 실시 예의 다양한 변경, 균등물, 및/또는 대체물을 포함하는 것으로 이해되어야 한다. 도면의 설명과 관련하여, 유사한 구성 요소에 대해서는 유사한 참조 부호가 사용될 수 있다. 단수의 표현은 문맥상 명백하게 다르게 뜻하지 않는 한, 복수의 표현을 포함할 수 있다. 본 문서에서, "A 또는 B", "A 및/또는 B 중 적어도 하나", "A, B 또는 C" 또는 "A, B 및/또는 C 중 적어도 하나" 등의 표현은 함께 나열된 항목들의 모든 가능한 조합을 포함할 수 있다. "제 1", "제 2", "첫째" 또는 "둘째" 등의 표현들은 해당 구성 요소들을, 순서 또는 중요도에 상관없이 수식할 수 있고, 한 구성 요소를 다른 구성 요소와 구분하기 위해 사용될 뿐 해당 구성 요소들을 한정하지 않는다. 어떤(예: 제 1) 구성 요소가 다른(예: 제 2) 구성 요소에 "(기능적으로 또는 통신적으로) 연결되어" 있다거나 "접속되어" 있다고 언급된 때에는, 상기 어떤 구성 요소가 상기 다른 구성 요소에 직접적으로 연결되거나, 다른 구성 요소(예: 제 3 구성 요소)를 통하여 연결될 수 있다.
본 문서에서 사용된 용어 "모듈"은 하드웨어, 소프트웨어 또는 펌웨어로 구성된 유닛을 포함하며, 예를 들면, 로직, 논리 블록, 부품, 또는 회로 등의 용어와 상호 호환적으로 사용될 수 있다. 모듈은, 일체로 구성된 부품 또는 하나 또는 그 이상의 기능을 수행하는 최소 단위 또는 그 일부가 될 수 있다. 예를 들면, 모듈은 ASIC(application-specific integrated circuit)으로 구성될 수 있다.
다양한 실시예들에 따르면, 기술한 구성 요소들의 각각의 구성 요소(예: 모듈 또는 프로그램)는 단수 또는 복수의 개체를 포함할 수 있다. 다양한 실시예들에 따르면, 전술한 해당 구성 요소들 중 하나 이상의 구성 요소들 또는 단계들이 생략되거나, 또는 하나 이상의 다른 구성 요소들 또는 단계들이 추가될 수 있다. 대체적으로 또는 추가적으로, 복수의 구성 요소들(예: 모듈 또는 프로그램)은 하나의 구성 요소로 통합될 수 있다. 이런 경우, 통합된 구성 요소는 복수의 구성 요소들 각각의 구성 요소의 하나 이상의 기능들을 통합 이전에 복수의 구성 요소들 중 해당 구성 요소에 의해 수행되는 것과 동일 또는 유사하게 수행할 수 있다. 다양한 실시예들에 따르면, 모듈, 프로그램 또는 다른 구성 요소에 의해 수행되는 단계들은 순차적으로, 병렬적으로, 반복적으로, 또는 휴리스틱하게 실행되거나, 단계들 중 하나 이상이 다른 순서로 실행되거나, 생략되거나, 또는 하나 이상의 다른 단계들이 추가될 수 있다.

Claims (20)

  1. 컴퓨터 시스템의 방법에 있어서,
    포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계; 및
    상기 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행하는 단계
    를 포함하는, 방법.
  2. 제 1 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계는,
    상기 포인터 기반 메모리 수집 기법의 함수들을 이용하여, 상기 포인터 및 시대 기반 메모리 수집 기법을 구현하고,
    상기 포인터 기반 메모리 수집 기법의 함수들은,
    공유 메모리에 지정된 로컬 포인터(I)가 스레드에 의해 보호되도록, 보호된 포인터 리스트에 상기 로컬 포인터(I)를 추가하기 위한 protect(I),
    상기 보호된 포인터 리스트에 있는 로컬 포인터(I)를 제거하기 위한 unprotect(I),
    상기 보호된 포인터에 있는 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는
    상기 보호된 포인터 리스트에 없는 로컬 포인터에 대한 수집을 위한 collect()
    중 적어도 하나를 포함하는, 방법.
  3. 제 2 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계는,
    상기 포인터 기반 메모리 수집 기법의 함수들과 함께, 상기 시대 기반 메모리 수집 기법의 함수들을 이용하여, 상기 포인터 및 시대 기반 메모리 수집 기법을 구현하고,
    상기 시대 기반 메모리 수집 기법의 함수들은,
    스레드가 활성 상태에서 상기 공유 메모리에 액세스하도록 설정하기 위한 set_active(),
    스레드가 비활성 상태에서 상기 공유 메모리에 액세스하기 않도록 설정하기 위한 set_quiescent(),
    활성 상태에 있는 스레드에 대해 생성된 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는
    활성 상태에 있는 스레드에 대해 폐기된 로컬 포인터에 대한 수집을 위한 collect()
    중 적어도 하나를 포함하는, 방법.
  4. 제 3 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법은,
    상기 protect(l)가 참(true)일 때, 스레드가 활성 상태에서 공유 메모리를 읽음으로써, 로컬 포인터(I)가 동일한 활성 상태에서 생성되는 보호 요건을 충족하는,
    방법.
  5. 제 4 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법은,
    상기 protect(l)가 참일 때, 상기 unprotect(l)는 상기 생성된 로컬 포인터(l)의 보호와 역참조 사이에 호출되지 않는 역참조 요건을 충족하는,
    방법.
  6. 제 2 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계는,
    이젝트하는(ejecting) 스레드와 이젝트되는(ejected) 스레드를 상기 이젝트되는 스레드의 상태 워드에서 서로 동기화하는 단계; 및
    상기 이젝트하는 스레드가 상기 이젝트되는 스레드의 상기 상태 워드를 변경하는 단계
    를 포함하는, 방법.
    `
  7. 제 6 항에 있어서,
    상기 상태 워드를 변경하는 단계는,
    상기 이젝트되는 스레드의 상태를 기반으로, 상기 상태 워드의 나머지 비트들에 상기 이젝트되는 스레드가 이젝트됨을 나타내는 플래그를 표시하는 단계; 및
    상기 이젝트되는 스레드의 보호된 포인터 리스트를 기반으로, 상기 이젝트되는 스레드의 상태를 업데이트하는 단계
    를 포함하는, 방법.
  8. 컴퓨터 시스템에 있어서,
    메모리; 및
    상기 메모리와 연결되고, 상기 메모리에 저장된 적어도 하나의 명령을 실행하도록 구성된 프로세서를 포함하고,
    상기 프로세서는,
    포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현하고,
    상기 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행하도록 구성되는,
    컴퓨터 시스템.
  9. 제 8 항에 있어서,
    상기 프로세서는,
    상기 포인터 기반 메모리 수집 기법의 함수들을 이용하여, 상기 포인터 및 시대 기반 메모리 수집 기법을 구현하고,
    상기 포인터 기반 메모리 수집 기법의 함수들은,
    공유 메모리에 지정된 로컬 포인터(I)가 스레드에 의해 보호되도록, 보호된 포인터 리스트에 상기 로컬 포인터(I)를 추가하기 위한 protect(I),
    상기 보호된 포인터 리스트에 있는 로컬 포인터(I)를 제거하기 위한 unprotect(I),
    상기 보호된 포인터에 있는 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는
    상기 보호된 포인터 리스트에 없는 로컬 포인터에 대한 수집을 위한 collect()
    중 적어도 하나를 포함하는, 컴퓨터 시스템.
  10. 제 9 항에 있어서,
    상기 프로세서는,
    상기 포인터 기반 메모리 수집 기법의 함수들과 함께, 상기 시대 기반 메모리 수집 기법의 함수들을 이용하여, 상기 포인터 및 시대 기반 메모리 수집 기법을 구현하고,
    상기 시대 기반 메모리 수집 기법의 함수들은,
    스레드가 활성 상태에서 상기 공유 메모리에 액세스하도록 설정하기 위한 set_active(),
    스레드가 비활성 상태에서 상기 공유 메모리에 액세스하기 않도록 설정하기 위한 set_quiescent(),
    활성 상태에 있는 스레드에 대해 생성된 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는
    활성 상태에 있는 스레드에 대해 폐기된 로컬 포인터에 대한 수집을 위한 collect()
    중 적어도 하나를 포함하는, 컴퓨터 시스템.
  11. 제 10 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법은,
    상기 protect(l)가 참(true)일 때, 스레드가 활성 상태에서 공유 메모리를 읽음으로써, 로컬 포인터(I)가 동일한 활성 상태에서 생성되는 보호 요건을 충족하는, 컴퓨터 시스템.
  12. 제 11 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법은,
    상기 protect(l)가 참일 때, 상기 unprotect(l)는 상기 생성된 로컬 포인터(l)의 보호와 역참조 사이에 호출되지 않는 역참조 요건을 충족하는, 컴퓨터 시스템.
  13. 제 9 항에 있어서,
    상기 프로세서는,
    이젝트하는 스레드와 이젝트되는 스레드를 상기 이젝트되는 스레드의 상태 워드에서 서로 동기화하고,
    상기 이젝트하는 스레드가 상기 이젝트되는 스레드의 상기 상태 워드를 변경하도록 구성되는,
    컴퓨터 시스템.
  14. 제 13 항에 있어서,
    상기 프로세서는,
    상기 이젝트되는 스레드의 상태를 기반으로, 상기 상태 워드의 나머지 비트들에 상기 이젝트되는 스레드가 이젝트됨을 나타내는 플래그를 표시하고,
    상기 이젝트되는 스레드의 보호된 포인터 리스트를 기반으로, 상기 이젝트되는 스레드의 상태를 업데이트하도록 구성되는,
    컴퓨터 시스템.
  15. 비-일시적인 컴퓨터-판독 가능 저장 매체에 있어서,
    포인터 기반 메모리 수집 기법과 시대 기반 메모리 수집 기법을 혼합하여, 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계; 및
    상기 포인터 및 시대 기반 메모리 수집 기법을 기반으로, 동시성 자료구조의 메모리 수집을 수행하는 단계
    를 실행하기 위한 하나 이상의 프로그램들을 저장하기 위한 컴퓨터-판독 가능 저장 매체.
  16. 제 15 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계는,
    상기 포인터 기반 메모리 수집 기법의 함수들을 이용하여, 상기 포인터 및 시대 기반 메모리 수집 기법을 구현하고,
    상기 포인터 기반 메모리 수집 기법의 함수들은,
    공유 메모리에 지정된 로컬 포인터(I)가 스레드에 의해 보호되도록, 보호된 포인터 리스트에 상기 로컬 포인터(I)를 추가하기 위한 protect(I),
    상기 보호된 포인터 리스트에 있는 로컬 포인터(I)를 제거하기 위한 unprotect(I),
    상기 보호된 포인터에 있는 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는
    상기 보호된 포인터 리스트에 없는 로컬 포인터에 대한 수집을 위한 collect()
    중 적어도 하나를 포함하는, 컴퓨터-판독 가능 저장 매체.
  17. 제 16 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계는,
    상기 포인터 기반 메모리 수집 기법의 함수들과 함께, 상기 시대 기반 메모리 수집 기법의 함수들을 이용하여, 상기 포인터 및 시대 기반 메모리 수집 기법을 구현하고,
    상기 시대 기반 메모리 수집 기법의 함수들은,
    스레드가 활성 상태에서 상기 공유 메모리에 액세스하도록 설정하기 위한 set_active(),
    스레드가 비활성 상태에서 상기 공유 메모리에 액세스하기 않도록 설정하기 위한 set_quiescent(),
    활성 상태에 있는 스레드에 대해 생성된 로컬 포인터(I)에 대한 수집을 위한 retire(I), 또는
    활성 상태에 있는 스레드에 대해 폐기된 로컬 포인터에 대한 수집을 위한 collect()
    중 적어도 하나를 포함하는, 컴퓨터-판독 가능 저장 매체.
  18. 제 17 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법은,
    상기 protect(l)가 참(true)일 때, 스레드가 활성 상태에서 공유 메모리를 읽음으로써, 로컬 포인터(I)가 동일한 활성 상태에서 생성되는 보호 요건; 및
    상기 protect(l)가 참일 때, 상기 unprotect(l)는 상기 생성된 로컬 포인터(l)의 보호와 역참조 사이에 호출되지 않는 역참조 요건
    을 충족하는, 컴퓨터-판독 가능 저장 매체.
  19. 제 16 항에 있어서,
    상기 포인터 및 시대 기반 메모리 수집 기법을 구현하는 단계는,
    이젝트하는 스레드와 이젝트되는 스레드를 상기 이젝트되는 스레드의 상태 워드에서 서로 동기화하는 단계; 및
    상기 이젝트하는 스레드가 상기 이젝트되는 스레드의 상기 상태 워드를 변경하는 단계
    를 포함하는,
    컴퓨터-판독 가능 저장 매체.
  20. 제 19 항에 있어서,
    상기 상태 워드를 변경하는 단계는,
    상기 이젝트되는 스레드의 상태를 기반으로, 상기 상태 워드의 나머지 비트들에 상기 이젝트되는 스레드가 이젝트됨을 나타내는 플래그를 표시하는 단계; 및
    상기 이젝트되는 스레드의 보호된 포인터 리스트를 기반으로, 상기 이젝트되는 스레드의 상태를 업데이트하는 단계
    를 포함하는, 컴퓨터-판독 가능 저장 매체.
KR1020200172853A 2020-12-11 2020-12-11 시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법 KR102546947B1 (ko)

Priority Applications (4)

Application Number Priority Date Filing Date Title
KR1020200172853A KR102546947B1 (ko) 2020-12-11 2020-12-11 시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법
JP2021098267A JP7214254B2 (ja) 2020-12-11 2021-06-11 エポックベースのメモリ収集技法とポインタベースのメモリ収集技法を混合するためのコンピュータシステム、方法および記録媒体
PCT/KR2021/008456 WO2022124507A1 (ko) 2020-12-11 2021-07-02 시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법
US17/510,149 US20220187986A1 (en) 2020-12-11 2021-10-25 Computer system for hybrid of epoch- and pointer-based memory reclamation, and method thereof

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
KR1020200172853A KR102546947B1 (ko) 2020-12-11 2020-12-11 시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법

Publications (2)

Publication Number Publication Date
KR20220083036A true KR20220083036A (ko) 2022-06-20
KR102546947B1 KR102546947B1 (ko) 2023-06-26

Family

ID=81941447

Family Applications (1)

Application Number Title Priority Date Filing Date
KR1020200172853A KR102546947B1 (ko) 2020-12-11 2020-12-11 시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법

Country Status (4)

Country Link
US (1) US20220187986A1 (ko)
JP (1) JP7214254B2 (ko)
KR (1) KR102546947B1 (ko)
WO (1) WO2022124507A1 (ko)

Families Citing this family (1)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
GB202110148D0 (en) * 2021-07-14 2021-08-25 Graphcore Ltd Synchronisation for a multi-tile processing unit

Citations (1)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US20170014748A1 (en) * 2015-07-13 2017-01-19 Nuvera Fuel Cells, LLC Regulating flow of pressure swing adsorbers

Family Cites Families (7)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US7478210B2 (en) * 2006-06-09 2009-01-13 Intel Corporation Memory reclamation with optimistic concurrency
IN2015DE02312A (ko) * 2015-07-29 2015-08-21 Pradeep Varma
US9785548B2 (en) * 2015-11-19 2017-10-10 Oracle International Corporation Hardware extensions for memory reclamation for concurrent data structures
US9959071B2 (en) * 2016-03-31 2018-05-01 Sandisk Technologies Llc Method and system for managing data in non-volatile memory
WO2018046085A1 (en) * 2016-09-08 2018-03-15 Huawei Technologies Co., Ltd. Systems and methods for performing a range query on a skiplist data structure
GB201703563D0 (en) * 2017-03-06 2017-04-19 Microsoft Technology Licensing Llc Safe manual memory management
US10599485B2 (en) * 2018-01-31 2020-03-24 Microsoft Technology Licensing, Llc Index structure using atomic multiword update operations

Patent Citations (1)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US20170014748A1 (en) * 2015-07-13 2017-01-19 Nuvera Fuel Cells, LLC Regulating flow of pressure swing adsorbers

Non-Patent Citations (1)

* Cited by examiner, † Cited by third party
Title
Balmau, Oana 외, "Fast and Robust Memory Reclamation for Concurrent DataStructures" , Proceedings of the 28th ACM Symposium on Parallelism in Algorithmsand Architectures(online), the U.S., Association* *

Also Published As

Publication number Publication date
KR102546947B1 (ko) 2023-06-26
JP7214254B2 (ja) 2023-01-30
JP2022093238A (ja) 2022-06-23
WO2022124507A1 (ko) 2022-06-16
US20220187986A1 (en) 2022-06-16

Similar Documents

Publication Publication Date Title
US11379324B2 (en) Persistent memory transactions with undo logging
Friedman et al. A persistent lock-free queue for non-volatile memory
Correia et al. Romulus: Efficient algorithms for persistent transactional memory
US8402218B2 (en) Efficient garbage collection and exception handling in a hardware accelerated transactional memory system
Harris et al. Transactional memory
KR101240092B1 (ko) 컴퓨터 플랫폼에서의 방법 및 컴퓨터 플랫폼
US11132294B2 (en) Real-time replicating garbage collection
US20100122073A1 (en) Handling exceptions in software transactional memory systems
US11620215B2 (en) Multi-threaded pause-less replicating garbage collection
JP2010524133A (ja) バッファリングされた書込みおよび強制的直列化順序を使用するトランザクショナルメモリ
Kang et al. A marriage of pointer-and epoch-based reclamation
KR102546947B1 (ko) 시대 기반 메모리 수집 기법과 포인터 기반 메모리 수집 기법 혼합을 위한 컴퓨터 시스템 및 그의 방법
US11016883B2 (en) Safe manual memory management
Meier et al. Virtual machine design for parallel dynamic programming languages
Tripp et al. FRC: a high-performance concurrent parallel deferred reference counter for C++
Juyal et al. An innovative approach to achieve compositionality efficiently using multi-version object based transactional systems
Mohamedin et al. ByteSTM: Virtual machine-level Java software transactional memory
Cai et al. Transactional Composition of Nonblocking Data Structures
Hassan et al. Integrating transactionally boosted data structures with stm frameworks: A case study on set
KR20210058613A (ko) 단일 파일의 병렬 읽기/쓰기를 위한 락킹 방법 및 이를 구현하는 컴퓨팅 장치
Dewan et al. Paving the way for distributed non-blocking algorithms and data structures in the partitioned global address space model
Bättig et al. Encapsulated open nesting for STM: fine-grained higher-level conflict detection
Bättig Efficient Synchronized-by-Default Concurrency
Peng et al. Conflict detection via adaptive signature for software transactional memory
Haubenschild et al. Lock-Free Buffer Managers Do Not Require Delayed Memory Reclamation

Legal Events

Date Code Title Description
E902 Notification of reason for refusal
E701 Decision to grant or registration of patent right
GRNT Written decision to grant