1

I know that there exists a int128_t type in C and C++.

If I have two threads one that is reading from a memory location containing this 128 bit integer and another that is writting to it.

Is there a chance that this value will be written as two 64 bit integer writes or will it be one 128 bit integer write?

Marcus Karpoff
  • 451
  • 5
  • 16
  • 6
    That type is not guaranteed to be defined on all implementations, and how a compiler generates assembly depends on the compiler, platform and compilation flags/options. There is no portable answer to this question. – François Andrieux May 25 '18 at 15:40
  • Possible duplicate of [Why isn't there int128\_t?](https://stackoverflow.com/questions/29638723/why-isnt-there-int128-t) – Achal May 25 '18 at 15:41
  • I wouldn't worry about. Use a proper synchronization technique and you should be fine. – NathanOliver May 25 '18 at 15:41
  • No, you do not know this, because it does not exist in C/C++. – SergeyA May 25 '18 at 15:43
  • If you are worried about race conditions (will the reader be reading while the writer is writing) then you are correct to do so. Tools for preventing race conditions are dependent on the language and OS, but some common ones are mutexes, critical sections, and signals. Mutexes are good when you want to make sure you're the only one doing something. – JohnH May 25 '18 at 15:43
  • Depends on the compiler's translation and the capabilities of the processor. If the processor can perform 128-bit transfers between memory and registers, the compiler will emit to do that. Otherwise, the compiler will emit enough instructions to transfer 128-bits. Anything from 16 8-bit transfers, block transfers or using DMA. This is a platform (implementation) issue, so there is nothing in the C or C++ standard specifically about how to implement. – Thomas Matthews May 25 '18 at 16:35
  • BTW, whether the 128 bits are read/written in a single instruction is immaterial to the read/write's atomicity. On AArch64 there are "load/store pair" instructions that transfer (up to) 128 bits from/to general registers in a single instruction, but the transfer is considered as two single-copy atomic transfers. – EOF May 25 '18 at 17:11

3 Answers3

5

Neither C nor C++ are required to have an int128_t type, although if a compiler does support that type then it must be a signed 2's complement 128 bit integral type. But atomicity is not a requirement.

The behaviour on reading and writing to any type simultaneously that is not atomic is undefined.

In C++, if you could use std::atomic<int128_t> and, if your platform does have an atomic int128_t then that will be little more than a typedef.

Otherwise, and in C, your compiler might have an atomic 128 bit integral type. If not then you could roll your own version using inline assembly.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • There is no `int128_t` in C++. – SergeyA May 25 '18 at 15:43
  • @SergeyA: Good point, although if they *do* have such a type then it needs to be a 128 bit 2's complement `signed`. – Bathsheba May 25 '18 at 15:45
  • I keep running into this issue where I need to write to this value maybe 0.1% of the execution time. But reads to this value happen about 10% of execution time. Using a most thread syncs are expensive. I was hoping to find a way around this cost but it looks like it will have to be payed. Thanks – Marcus Karpoff May 25 '18 at 15:56
  • @MarcusKarpoff - consider using something like an assembly bus lock. That will be an order of magnitude faster than a mutex, and probably no more expensive than a pipeline dump. – Bathsheba May 25 '18 at 16:16
5

The support is discussed in other answers. I'll discuss implementation issues.

Usually when reading from memory, the compiler will emit processor instructions to fetch the data from memory into a register. This may be atomic depending on how the databus is set up between the processor and the memory.

If your processor supports 128-bit transfers and the memory supports 128-bit data bus, this could be a single fetch (or write).

If your processor supports 128-bit {register} transfers, but the data bus is smaller, the processor will perform enough fetches to transfer the data from memory. This may or may not be atomic, depending on your definition of atomic (it's one processor instruction, but may require more than one fetch).

For processors that don't support 128-bit register transfers, the compiler will emit enough instructions to read the memory into register(s). This is for register to memory or memory to register transfers.

For memory to memory transfers (e.g. variable assignments), the compiler may choose to use block reading and writing (if your processor has support for block reading and writing). Some processors support SIMD, others may have block transfer instructions. For example, the ARM has LDM (load multiple) and STM (store multiple) instructions for loading many registers from memory and storing many registers to memory. Another method of block reading and writing is to use a DMA device (if present). The DMA can transfer data while the processor executes other instructions. However, the overhead to use the DMA may require more instructions than using 16 8-byte (byte) transfers.

In summary, compilers are not required to support int128_t. If they do support it, there are various methods to transfer the data, depending on the processor and platform hardware support. View the assembly language to see the instructions emitted by the compiler to support int128_t.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
3

First off, there is no int128_t type in C++. The largest standard type is int64_t.

Second off, some platforms provide a 128-bit integer type as an extension. For example, gcc/clang/icc support __int128 type.

To correctly use this type in multithreading scenarios, one has (as with any other type!) either protect the access with appropriate synchronization constructs, or use std::atomic<__int128>. Platforms which support __int128, usually support atomic version of it as well.

And just to satisfy your curiosity, I do not know any common hardware currently in use which could support 128 bit integers natively.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • some platforms and VISs do support 128-bit pointers at least for future compatibily. underlying cpus are 64bit. that explaiins existence of such in nearly all major compilers (intel, pgi, lahey supported under different names) – Swift - Friday Pie May 25 '18 at 17:21