스레드 로컬 스토리지
Thread-local storage이 글은 검증을 위해 인용구가 추가로 필요하다. 로컬 – · · 책 · · (2012년 12월) (이 템플릿 하는 |
TLS(Trad-Local Storage)는 스레드에 로컬인 정적 메모리 또는 전역 메모리를 사용하는 컴퓨터 프로그래밍 방식이다.
일반적으로 현대 프로그래밍에서는 글로벌 변수의 사용이 금지되지만, UNIX와 같은 레거시 운영 체제는 단프로세서 하드웨어용으로 설계되어 사전 리엔트론 API의 의미론을 유지하기 위한 몇 가지 추가적인 메커니즘이 필요하다.그러한 상황의 예로는 함수가 전역 변수를 사용하여 오류 조건(예: 전역 변수)을 설정하는 경우를 들 수 있다.errno
C 라이브러리의 많은 기능에 의해 사용됨).만약errno
전역 변수인 경우, 한 스레드에서 시스템 함수를 호출하면 다른 스레드에서 시스템 함수를 호출하여 이전에 설정한 값을 덮어쓸 수 있으며, 다른 스레드에서 코드를 추적하기 전에 오류 상태를 확인할 수 있다.해결책은 가지고 있는 것이다.errno
글로벌한 것처럼 보이지만 실은 한 스레드당 한 번 존재하는 변수, 즉 스레드 로컬 스토리지에 산다.두 번째 사용 사례는 정보를 글로벌 변수에 축적하는 다중 스레드가 될 수 있다.경주 조건을 피하려면 이 전역 변수에 대한 모든 액세스가 뮤텍스로 보호되어야 한다.또는 각 스레드는 스레드-로컬 변수(정의상 다른 스레드에서 읽거나 쓸 수 없으므로 레이스 조건이 있을 수 없음을 의미함)로 누적될 수 있다.스레드는 자신의 스레드-로컬 변수에서 하나의 진정한 글로벌 변수로 최종 축적을 동기화하기만 하면 된다.
많은 시스템이 스레드 로컬 메모리 블록의 크기에 제한을 가하며, 사실 종종 다소 엄격한 제한을 가한다.한편, 시스템이 최소한 메모리 주소(점자) 크기의 가변 스레드를 로컬로 제공할 수 있는 경우, 이러한 메모리 블록을 동적으로 할당하고 해당 블록의 메모리 주소를 스레드 로컬 변수에 저장함으로써 임의 크기의 메모리 블록을 스레드 로컬 방식으로 사용할 수 있다.RISC 기계에서 호출 규약은 종종 이 사용을 위해 스레드 포인터 레지스터를 예약한다.
윈도 구현
응용 프로그램 프로그래밍 인터페이스(API) 기능TlsAlloc
사용되지 않은 TLS 슬롯 인덱스를 가져오는 데 사용될 수 있으며, TLS 슬롯 인덱스는 '사용된' 것으로 간주된다.
그TlsGetValue
그리고TlsSetValue
그런 다음 TLS 슬롯 인덱스로 식별된 스레드 로컬 변수에 메모리 주소를 읽고 쓰는 데 함수를 사용한다. TlsSetValue
현재 스레드의 변수에만 영향을 미친다.그TlsFree
함수를 호출하여 TLS 슬롯 인덱스를 해제할 수 있다.
각 스레드에 대해 Win32 스레드 정보 블록이 있다.이 블록의 항목 중 하나는 해당 스레드에 대한 스레드 로컬 저장소 테이블이다.[1]TLSAlloc은 각 호출에 대해 주소 공간별로 고유한 인덱스를 이 테이블에 반환한다.각 스레드는 스레드 로컬 저장소 테이블의 고유한 복사본을 가지고 있다.따라서 각 스레드는 TLSSetValue(인덱스)를 독립적으로 사용할 수 있고 TLSGetValue(인덱스)를 통해 지정된 값을 얻을 수 있는데, 이는 이들 스레드가 스레드의 자체 테이블에서 항목을 설정하고 조회하기 때문이다.
TLSXxx 함수 패밀리와 별도로 윈도우즈 실행 파일은 실행 프로세스의 각 스레드에 대해 다른 페이지에 매핑되는 섹션을 정의할 수 있다.TLSXXX 값과 달리 이 페이지에는 임의의 유효한 주소가 포함될 수 있다.그러나 이러한 주소는 실행 중인 각 스레드에 대해 다르기 때문에 비동기 함수(다른 스레드에서 실행될 수 있음)로 전달되거나 전체 프로세스 내에서 가상 주소가 고유하다고 가정하는 코드로 전달되지 않아야 한다.TLS 섹션은 메모리 페이징을 사용하여 관리되며 그 크기는 페이지 크기(x86 컴퓨터의 4kB)로 정량화된다.이러한 섹션은 프로그램의 주요 실행 파일 내에서만 정의될 수 있다. LoadLibrary로 로드할 때 DLL이 올바르게 초기화되지 않기 때문에 DLL은 이러한 섹션을 포함해서는 안 된다.
프스레드 구현
Pthreads API에서 스레드에 로컬인 메모리는 스레드별 데이터라는 용어로 지정된다.
기능pthread_key_create
그리고pthread_key_delete
스레드 특정 데이터에 대한 키를 만들고 삭제하는 데 각각 사용된다.키의 형식은 명백하게 불투명하게 남아 있으며, 이를 가리킨다.pthread_key_t
. 이 키는 모든 실로 볼 수 있다.각 스레드에서 키를 스레드별 데이터와 연결할 수 있음pthread_setspecific
데이터를 나중에 검색할 수 있다.pthread_getspecific
.
게다가.pthread_key_create
스레드 특정 데이터가 NULL이 아닌 경우 스레드 종료 시 자동으로 호출되는 소멸기 함수를 선택적으로 수락할 수 있다.소멸자는 키와 관련된 값을 매개 변수로 수신하여 정리 작업(접속 연결, 여유 메모리 등)을 수행할 수 있다.소멸자가 지정되어 있더라도 프로그램은 여전히 호출해야 한다.pthread_key_delete
프로세스 수준에서 스레드 특정 데이터를 확보하십시오(파괴자는 스레드에 로컬로 데이터를 분리할 수만 있음).
언어별 구현
프로그래머에 의존하여 적절한 API 기능을 호출하는 것 외에, 스레드 로컬 스토리지(TLS)를 지원하기 위해 프로그래밍 언어를 확장하는 것도 가능하다.
C와 C++
C11에서 키워드_Thread_local
스레드 로컬 변수를 정의하는 데 사용된다.머리글<threads.h>
, 지원되는 경우 정의thread_local
그 키워드의 동의어로.사용 예:
#include <threads.h> 스레드_로컬 인트로 foo = 0;
C++11에서는thread_local
[2] 다음 경우에 사용할 수 있는 키워드
- 네임스페이스 수준(글로벌) 변수
- 파일 정적 변수
- 함수 정적 변수
- 정적 부재 변수
이와 별도로 다양한 컴파일러 구현은 스레드 로컬 변수를 선언하는 구체적인 방법을 제공한다.
- Solaris Studio C/C++, IBM XL C/C++,[3] GNU C,[4] Clang[5] 및 Intel C++ Compiler(리눅스 시스템)[6]는 다음 구문을 사용한다.
__thread int number;
- Visual C++,[7] Intel C/C++(윈도우즈 시스템),[8] C++Builder 및 Digital Mars C++는 다음 구문을 사용한다.
__declspec(thread) int number;
- C++Builder는 구문도 지원한다.
int __thread number;
Vista 및 Server 2008 이전 버전의 Windows에서는__declspec(thread)
DLL이 실행 파일에 바인딩되어 있을 때만 DLL에서 작동하며 LoadLibrary()로 로드된 DLL에서는 작동하지 않는다(보호 결함 또는 데이터 손상이 발생할 수 있음).[7]
Common Lisp(및 다른 방언)
Common Lisp은 동적 범위 변수라는 기능을 제공한다.
동적 변수는 함수의 호출에 사적인 결합을 가지며, 모든 어린이는 함수에 의해 호출된다.
이러한 추상화는 자연스럽게 스레드별 스토리지에 매핑되며, 스레드를 제공하는 Lisp 구현이 이를 실현한다.Common Lisp에는 수많은 표준 동적 변수가 있으므로 이러한 변수가 동적 바인딩에서 스레드-로컬 의미론을 가지지 않고는 스레드를 언어 구현에 현명하게 추가할 수 없다.
예를 들어 표준 변수*print-base*
정수가 인쇄되는 기본 방사선을 결정한다.이 변수가 재정의된 경우, 모든 포함 코드는 다음 대체 라디ix로 정수를 인쇄한다.
;;; function foo와 그 아이들이 인쇄할 것이다. ;;; 16진수: (하게 하다 ((*인쇄 기반* 16)) (foo))
기능이 다른 스레드에서 동시에 실행될 수 있는 경우, 이 바인딩은 로컬 스레드여야 하며, 그렇지 않으면 각 스레드는 글로벌 인쇄 라디스를 누가 제어하는지를 놓고 싸울 것이다.
D
D 버전 2에서 모든 정적 및 전역 변수는 기본적으로 스레드 로컬이며 다른 언어의 "정상" 글로벌 및 정적 변수와 유사한 구문으로 선언된다.글로벌 변수는 공유 키워드를 사용하여 명시적으로 요청해야 함:
인트로 스레드 로컬; // 이것은 스레드 로컬 변수다. 공유했습니다. 인트로 전지구적; // 모든 스레드와 공유되는 전역 변수.
공유 키워드는 스토리지 클래스 및 유형 한정자로 모두 작동하며, 공유 변수는 정적으로 데이터 무결성을 강제하는 일부 제한의 적용을 받는다.[9]이러한 제한 없이 "클래식" 글로벌 변수를 선언하려면 안전하지 않은 __gshared 키워드를 사용해야 한다.[10]
__gshared 인트로 전지구적; // 이것은 명백한 오래된 글로벌 변수다.
자바
Java에서 스레드 로컬 변수는 에 의해 구현된다.ThreadLocal
계급의 목적ThreadLocal은 get/set 방법을 통해 액세스할 수 있는 T 유형의 변수를 보유한다.예를 들어 정수 값을 가진 ThreadLocal 변수는 다음과 같이 보인다.
사유의 정태의 최종의 스레드로컬<정수> mythreadLocalInteger = 새로운 스레드로컬<정수>();
적어도 Oracle/OpenJDK의 경우 OS 스레드가 Java 스레딩의 다른 측면에 사용되더라도 기본 스레드 로컬 스토리지를 사용하지 않는다.대신 각 스레드 객체는 스레드 객체의 (스레드-안전하지 않은) 맵을 해당 값에 저장한다(각 스레드 로컬에 스레드 객체의 맵이 값을 지정하여 성능 오버헤드가 발생하는 것과는 반대로).[11]
.NET 언어:C# 등
.NET Framework 언어(예: C#)에서 정적 필드는 TradStatic 속성으로 표시할 수 있다.
계급 푸바 { [스레드 정적] 사유의 정태의 인트로 _foo; }
.NET 4.0에서 시스템.실타래.스레드로컬<T> 클래스는 스레드 로컬 변수를 할당하고 느리게 로드하는 데 사용할 수 있다.
계급 푸바 { 사유의 정태의 시스템.스레딩.스레드로컬<인트로> _foo; }
또한 스레드 로컬 변수를 동적으로 할당하는 데 API를 사용할 수 있다.
객체 파스칼
Object Pascal(Delphi) 또는 Free Pascal에서는 'var' 대신 sradvar 예약된 키워드를 사용하여 스레드 로컬 저장소를 사용하여 변수를 선언할 수 있다.
시합을 하다 mydata_process: 정수의; 스레드바 mydata_mydatalocal: 정수의;
목표-C
코코아, GNUstep, OpenStep에서 각 물체는 실의 방법을 통해 접근할 수 있는 실 로컬 사전을 가지고 있다.
NSMutableDictionary *받아쓰게 하다 = [[NSThread currentThread] 스레드디커버리]; 받아쓰게 하다[@"A 키"] = @"일부 데이터";
펄
Perl 스레드는 언어의 진화에 늦게 추가되었는데, 그 후, CCAN(Comprehensive Perl Archive Network)에 현존하는 코드의 큰 본체가 이미 존재하였다.따라서 Perl의 스레드는 스레드가 기존의 비 스레드 인식 코드에 미치는 영향을 최소화하기 위해 기본적으로 모든 변수에 대한 자체 로컬 스토리지를 취한다.Perl에서는 다음 속성을 사용하여 스레드 공유 변수를 생성할 수 있다.
사용하다 실; 사용하다 스레드:슬라이드:슬라이드; 나의 $localvar; 나의 $sharedvar :공유했습니다.;
퓨어 베이직
PureBasic에서는 스레드 키워드로 스레드 변수를 선언한다.
나사산 VAR
파이톤
파이썬 버전 2.4 이상에서는 스레드 로컬 스토리지를 만들기 위해 스레드 모듈의 로컬 클래스를 사용할 수 있다.
수입하다 실타래질 마이데이터 = 실타래질.국부적() 마이데이터.x = 1
루비
Ruby는 []=/[] 방법을 사용하여 스레드 로컬 변수를 생성/액세스할 수 있다.
나사산.현재의[:user_id] = 1
녹
스레드 로컬 변수는 를 사용하여 러스트에서 생성할 수 있다.thread_local!
러스트 표준 라이브러리에서 제공하는 매크로:
std::cell 사용:::RefCell, 사용 std::스레드,thread_local!(정적 FOO:RefCell<, u32>^RefCell:: 새로운(1));FOO.with(f{assert_eq!(*f.borrow(), 1);*f.borrow_mut()=2;});각각의 스레드 1의 초기 값으로부터 시작,//비록 이 스레드 2 하지).:spawn(움직임{FOO.with(f{다고 주장하는 스레드 로컬 값의 복사본을 바꾸었다._eq!(*f.borrow(), 1); *f.borrow_mut() = 3; }); }); // wait for the thread to complete and bail out on panic t.join().unwrap(); // original thread retains the original value of 2 despite the child thread changing the value to 3 for that thread FOO.with( f { assert_eq!(*f.borrow(), 2); });
참조
- ^ Pietrek, Matt (May 2006). "Under the Hood". MSDN. Retrieved 6 April 2010.
- ^ C++11 표준의 섹션 3.7.2
- ^ IBM XL C/C++: 스레드 로컬 스토리지
- ^ GCC 3.3.1: 스레드 로컬 스토리지
- ^ 클랑 2.0: 릴리스 노트
- ^ Intel C++ Compiler 8.1(리눅스) 릴리스 정보:스레드 로컬 스토리지
- ^ a b Visual Studio 2003: "Thread Local Storage (TLS)". Microsoft Docs.
- ^ Intel C++ 컴파일러 10.0(윈도우즈):스레드 로컬 스토리지
- ^ Alexandrescu, Andrei (6 July 2010). Chapter 13 - Concurrency. The D Programming Language. InformIT. p. 3. Retrieved 3 January 2014.
- ^ Bright, Walter (12 May 2009). "Migrating to Shared". dlang.org. Retrieved 3 January 2014.
- ^ "How is Java's ThreadLocal implemented under the hood?". Stack Overflow. Stack Exchange. Retrieved 27 December 2015.
외부 링크
- 특정 하드웨어에 대한 OpenMP Parallell 프로세서 지원
- Shared_memory 메모리 페이지 및 구성(지원되는 경우 cpu 및 커널 지원)
- 컨텍스트_스위치 작업 스위칭, 스레드, 페이지는 하드웨어 가속 및 커널 제공이라고도 함
- Semaphore_(프로그래밍) LOCK, (cpu)가 다중 포트 메모리를 충분히 지원하지 않는 경우(cpu 동결 방지)
- 스레드 로컬 스토리지에 대한 ELF 처리 — 구현에 대한 문서 C 또는 C++.
- ACE_TSS< TYPE > 클래스 템플릿 참조
- RWTThreadLocal<유형> 클래스 템플릿 설명서
- Doug Doedens의 "스레드 로컬 스토리지를 사용하여 스레드 특정 데이터 전달" 기사
- 로렌스 크롤의 "스레드 로컬 스토리지"
- 월터 브라이트의 기사 "공유하는 것이 항상 좋은 것은 아니다"
- Java의 실제 ThreadLocal 사용량: http://www.captechconsulting.com/blogs/a-persistence-pattern-using-threadlocal-and-ejb-interceptors
- GCC "[1]"
- 녹 "[2]"