-1
atomic_compare_exchange_strong_explicit(mem, old, new, <mem_order>, <mem_order>);
ftruncate(fd, <size>);

All I want is that these two lines of code always occur without any interference (WITHOUT USING LOCKS). Immediately after that CAS, ftruncate(2) should be called. I read a small description about memory orders, although I don’t understand them much. But they seemed to make this possible. Is there any way around?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Mihir Luthra
  • 6,059
  • 3
  • 14
  • 39
  • 1
    you are asking for an atomic section of code without locking... well I'm afraid you will need a lock... that said, if fd is accessed for write without locking, you already have a problem... – OznOg May 25 '19 at 13:53
  • Well wish there was some. I am ejecting my library into processes whose state is unknown and using locks may cause a deadlock. – Mihir Luthra May 25 '19 at 14:13
  • 1
    if taking a lock leads to deadlock, then you have either a design problem either a code fail, but there is no real reason for deadlocking here... – OznOg May 25 '19 at 14:21
  • 1
    It's worse than that -- even *with* locks, it is difficult or even impossible to prevent a context switch from occuring between the CAS and `ftruncate`, or to prevent a concurrently-running thread from making progress. Indeed "immediately after" is not even well defined on systems with multiple concurrently-operating execution units, except in the trivial sense of considering only actions occurring in one thread. – John Bollinger May 25 '19 at 15:08
  • Your title asks for the things to occur in order. That's easy, and C++ does that automatically with `mo_seq_cst`; all visible side-effects of CAS will appear before any from `ftruncate`. What kind of interference are you worried about? Some other thread changing the size of the file? You can't prevent that race condition. – Peter Cordes May 25 '19 at 16:09
  • Thanks for the answer. I was assuming for something like that to exist. I had read some concept named transactional memory on google, sorry I don’t remember where I read it so can’t share link, and with that in mind I thought there maybe some way. – Mihir Luthra May 25 '19 at 18:53

1 Answers1

2

Your title asks for the things to occur in order. That's easy, and C basically does that automatically with mo_seq_cst; all visible side-effects of CAS will appear before any from ftruncate.

(Not strictly required by the ISO C standard, but in practice real implementations implement seq-cst with a full barrier, except AArch64 where STLR doesn't stall to drain the store buffer unless/until there's a LDAR while the seq-cst store is still in the store buffer. But a system call is definitely going to also include a full barrier.)

Within the thread doing the operation, the atomic is Sequenced Before the system call.

What kind of interference are you worried about? Some other thread changing the size of the file? You can't prevent that race condition.

There's no way to combine some operation on memory + a system call into a single atomic transaction. You would need to use a hypothetical system call that atomically does what you want. (Presumably it would have to do locking inside the kernel to make a file operation and a memory modification appear as one atomic transaction.) e.g. the Linux futex system call atomically does a couple things, but of course there's nothing like this for any other operations.

Or you need locking. (Or to suspend all other threads of your process somehow.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Even if you had a syscall doing exactly these two things, that wouldn't mean they are atomic; a lock on a fs object is unlikely to protect a memory object. – curiousguy May 31 '19 at 19:20