x86, arm, GCC 및 icc에서 작동하는 Linux에서 원자 연산을 수행하는 방법은 무엇입니까?
모든 Modern OS는 오늘날 몇 가지 원자 적 작업을 제공합니다.
- Windows에는
Interlocked*
API가 있습니다. - FreeBSD는
<machine/atomic.h>
- Solaris는
<atomic.h>
- Mac OS X에는
<libkern/OSAtomic.h>
Linux에서 이와 비슷한 것이 있습니까?
- x86, x86_64 및 arm을 포함한 대부분의 Linux 지원 플랫폼에서 작동하려면이 기능이 필요합니다 .
- 적어도 GCC 및 인텔 컴파일러에서 작업하려면이 파일이 필요합니다.
- glib 또는 qt와 같은 3rd par 라이브러리를 사용할 필요가 없습니다.
- C ++에서 작동하려면 필요합니다 (C는 필요하지 않음).
문제 :
- GCC 원자 내장 기능
__sync_*
은 모든 플랫폼 (ARM)에서 지원되지 않으며 인텔 컴파일러에서 지원되지 않습니다. - AFAIK
<asm/atomic.h>
는 사용자 공간에서 사용해서는 안되며 성공적으로 사용하지 않았습니다. 또한 인텔 컴파일러에서 작동하는지 확실하지 않습니다.
어떤 제안?
나는 많은 관련 질문이 있다는 것을 알고 있지만 그중 일부는 __sync*
나에게 적합하지 않은 (ARM)을 가리키고 일부는 asm/atomic.h
.
GCC를 위해 이것을 수행하는 인라인 어셈블리 라이브러리가있을 수 있습니다 (ICC는 gcc 어셈블리를 지원합니다)?
편집하다:
추가 작업만을위한 매우 부분적인 솔루션이 있습니다 (원자 카운터 구현은 허용하지만 CAS가 필요한 잠금 구조는 허용하지 않음).
당신이 사용하는 경우 libstc++
(인텔 컴파일러의 사용을 libstdc++
) 당신은 사용할 수 있습니다 __gnu_cxx::__exchange_and_add
그 정의 <ext/atomicity.h>
나 <bits/atomicity.h>
. 컴파일러 버전에 따라 다릅니다.
그러나 여전히 CAS를 지원하는 것을보고 싶습니다.
프로젝트는 이것을 사용하고 있습니다 :
http://packages.debian.org/source/sid/libatomic-ops
CAS와 같은 간단한 작업을 원한다면 커널에서 아치 특정 구현을 사용하고 autotools / cmake를 사용하여 사용자 공간에서 아치 검사를 수행 할 수 없습니까? 라이센스에 관한 한 커널은 GPL이지만 커널에 라이센스가있는 것이 아니라 이러한 작업을위한 인라인 어셈블리가 Intel / AMD에서 제공된다는 것이 논쟁의 여지가 있다고 생각합니다. 커널 소스에서 쉽게 접근 할 수있는 형태 일뿐입니다.
C & C ++의 최근 표준 (2011 년부터)은 이제 원자 연산을 지정합니다.
- C11 :
stdatomic.h
- C ++ 11 :
std::atomic
그럼에도 불구하고 플랫폼 또는 컴파일러는 이러한 최신 헤더 및 기능을 지원하지 않을 수 있습니다.
꿰매다. 나는 GCC 프리미티브를 제안하려고했는데 당신은 그들이 한계를 벗어났다고 말했습니다. :-)
이 경우 #ifdef
관심있는 각 아키텍처 / 컴파일러 조합에 대해 수행하고 인라인 asm을 코딩합니다. 그리고 어쩌면 확인 __GNUC__
또는 이와 유사한 매크로 그들이 사용할 수있는 경우가 훨씬 더 잘들을 사용하는 느낌 때문에 GCC 프리미티브를 사용합니다. :-)
중복이 많고 정확성을 확인하는 것이 어려울 수 있지만 이것이 많은 프로젝트에서이 작업을 수행하는 방식 인 것 같고 좋은 결과를 얻었습니다.
과거에 비트 날이 몇 개는 : GCC를 사용하는 경우, "잊지 마세요 "를위한 쳤을 및 등asm volatile
"memory"
"cc"
비침 입적 라이선스가있는 Boost와 다른 프레임 워크는 대상 플랫폼에서 지원되는 한 이미 휴대용 원자 카운터를 제공합니다.
타사 라이브러리는 우리에게 좋습니다. 그리고 이상한 이유로 회사에서 사용을 금지 한 경우에도 원하는 것을 구현하기 위해 (라이센스가 허용하는 한) 어떻게 진행되는지 확인할 수 있습니다.
나는 최근에 그런 일을 구현했고 당신과 같은 어려움에 직면했습니다. 내 솔루션은 기본적으로 다음과 같습니다.
- 기능 매크로로 gcc 내장을 감지하십시오.
- 다만 같은 구현을 사용할 수없는 경우
cmpxch
와__asm__
다른 아키텍처를 (ARM은 좀 더 복잡보다)입니다. 가능한 한 가지 크기에 대해 수행하십시오sizeof(int)
. - 모든 다른 하나의 상단에 기능 또는 두 개의 프리미티브 구현
inline
기능을
ARM 원자 연산을 지원하는 GCC 용 패치가 있습니다. 인텔에서는 도움이되지 않지만 코드를 살펴볼 수 있습니다. 최신 ARM 아키텍처에 대한 최신 커널 지원이 있고 최신 커널에는 명령어가 내장되어 있으므로 작동하는 것을 빌드 할 수 있습니다.
http://gcc.gnu.org/ml/gcc-patches/2011-07/msg00050.html
__sync*
GCC에서 이러한 빌드를 채택했기 때문에 인텔 컴파일러가 확실히 지원하고 있습니다. 이 페이지 의 첫 번째 단락 을 읽으십시오 . 또한 " Linux * 용 인텔 ® C ++ 컴파일러 참조 ", 198 페이지를 참조하십시오. 2006 년에 작성 되었으며 이러한 내장 기능에 대해 정확히 설명합니다.
ARM 지원과 관련하여, 구형 ARM CPU의 경우 : 사용자 공간에서 완전히 수행 할 수는 없지만 커널 공간에서 수행 할 수 있습니다 (작업 중에 인터럽트를 비활성화하여). 지금은 꽤 오랫동안 지원되는 곳에서 읽은 것 같습니다.
이 PHP 버그 에 따르면 2011-10-08 날짜 __sync_*
는
- Linux 이외의 다른 제품을 사용하는 PA-RISC
- SPARCv7 이하
- GCC가 4.3 미만인 ARM
- Linux 이외의 ARMv5 이하
- MIPS1
따라서 GCC> 4.3 (및 4.7이 현재 버전 임)에서는 ARMv6 이상에서 문제가 없어야합니다. Linux 용으로 컴파일하는 한 ARMv5에서도 문제가 없어야합니다.
Debian / Ubuntu 권장 사항 ...
sudo apt-get libatomic-ops-dev 설치
예 : http://www.hpl.hp.com/research/linux/atomic_ops/example.php4
GCC 및 ICC 호환.
compared to Intel Thread Building Blocks (TBB), using atomic< T >, libatomic-ops-dev is over twice as fast! (Intel compiler)
Testing on Ubuntu i7 producer-consumer threads piping 10 million ints down a ring buffer connection in 0.5secs as opposed to 1.2secs for TBB
And easy to use e.g.
volatile AO_t head;
AO_fetch_and_add1(&head);
See: kernel_user_helpers.txt or entry-arm.c and look for __kuser_cmpxchg
. As seen in comments of other ARM Linux versions,
kuser_cmpxchg
Location: 0xffff0fc0 Reference prototype: int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr); Input: r0 = oldval r1 = newval r2 = ptr lr = return address Output: r0 = success code (zero or non-zero) C flag = set if r0 == 0, clear if r0 != 0 Clobbered registers: r3, ip, flags Definition: Atomically store newval in *ptr only if *ptr is equal to oldval. Return zero if *ptr was changed or non-zero if no exchange happened. The C flag is also set if *ptr was changed to allow for assembly optimization in the calling code. Usage example:
typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
int atomic_add(volatile int *ptr, int val)
{
int old, new;
do {
old = *ptr;
new = old + val;
} while(__kuser_cmpxchg(old, new, ptr));
return new;
}
Notes:
- This routine already includes memory barriers as needed.
- Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12).
This is for use with Linux with ARMv3 using the swp
primitive. You must have a very ancient ARM not to support this. Only a data abort or interrupt can cause the spinning to fail, so the kernel monitors for this address ~0xffff0fc0 and performs a user space PC
fix-up when either a data abort or an interrupt occurs. All user-space libraries that support ARMv5 and lower will use this facility.
For instance, QtConcurrent uses this.
ReferenceURL : https://stackoverflow.com/questions/2287451/how-to-perform-atomic-operations-on-linux-that-work-on-x86-arm-gcc-and-icc
'development' 카테고리의 다른 글
Youtube 삽입 : 프레임에 액세스하려는 안전하지 않은 JavaScript 시도 (0) | 2021.01.08 |
---|---|
초기 거부 후 getUserMedia ()로 권한을 다시 요청합니다. (0) | 2021.01.08 |
Google App Engine에서 스테이징 환경을 설정하는 방법 (0) | 2021.01.08 |
문자열의 시작이 in보다 느린 이유는 무엇입니까? (0) | 2021.01.08 |
Objective-C의 속성 및 인스턴스 변수 (0) | 2021.01.08 |