1

Using shared memory with the shmget() system call, the aim of my C++ program, is to fetch a bid price from the Internet through a server written in Rust so that each times the value changes, I m performing a financial transaction.

Server pseudocode

Shared_struct.price = new_price

Client pseudocode

Infinite_loop_label:
     Wait until memory address pointed by Shared_struct.price changes.
     Launch_transaction(Shared_struct.price*1.13)
Goto Infinite_loop

Since launching a transaction involve paying transaction fees, I want to create a transaction only once per buy price change.

Using a semaphore or a futex, I can do the reverse, I m meaning waiting for a variable to reachs a specific value, but how to wait until a variable is no longer equal to current value?

Whereas on Windows I can do something like this on the address of the shared segment:

ULONG g_TargetValue; // global, accessible to all process
ULONG CapturedValue;
ULONG UndesiredValue;

UndesiredValue = 0;
CapturedValue = g_TargetValue;
while (CapturedValue == UndesiredValue) {
      WaitOnAddress(&g_TargetValue, &UndesiredValue, sizeof(ULONG), INFINITE);
      CapturedValue = g_TargetValue;
}

Is there a way to do this on Linux? Or a straight equivalent?

user2284570
  • 2,891
  • 3
  • 26
  • 74
  • Of course, the source code of the server can be modified. The aim is to always be the highest bider during an auction. – user2284570 Dec 11 '20 at 19:22
  • Have the server trigger a semaphore when it updates the value, then wait on that semaphore instead of the value itself – that other guy Dec 11 '20 at 20:39
  • @thatotherguy not yet (my aim is to modify the server). The problem with this is what warrenty that while the server lock the semaphore immediatly again that the client won t loop several times for the same transaction parameter? Whereas if it wait on the variable itself it will be locked immediatly again until the new value changes again. – user2284570 Dec 11 '20 at 22:40
  • Why would your client loop several times instead of wait for the next signal? – that other guy Dec 11 '20 at 22:46
  • @thatotherguy do you mean that the client should wait to receive the signal? I m using shared memory for latency (this is a race to maintain the highest bid until the auction ends over the 10 second period) and I m afraid saving and restoring context would take time. Also concerning internal variables what if the process is signaled while doing a new transaction? – user2284570 Dec 11 '20 at 22:58
  • @thatotherguy there should be a systemd call to this. I just saw java has the `synchronized` keyword allowing to act on a variable only if it changes. https://stackoverflow.com/a/63387140 – user2284570 Dec 11 '20 at 23:02
  • @thatotherguy I found it appears an other operating system not supporting the Zfs filesystem required to run the server (so which doesn t solve my problem) has the exact thing I m needing. – user2284570 Dec 13 '20 at 14:02

1 Answers1

-1

You can use futex. (I assumed "var" is in shm mem)

/* Client */

int prv;

while (1) {
  int prv = var;
  int ret = futex(&var, FUTEX_WAIT, prv, NULL, NULL, 0);
  /* Spurious wake-up */
  if (!ret && var == prv) continue;
  doTransaction();
}

/* Server */

int prv = NOT_CACHED;
while(1) {
  var = updateVar();
  if (var != prv || prv = NOT_CACHED)
    futex(&var, FUTEX_WAKE, 1, NULL, NULL, 0);
  prv = var;
}

It requires the server side to call futex as well to notify client(s).

Note that the same holds true for WaitOnAddress.

According to MSDN:

Any thread within the same process that changes the value at the address on which threads are waiting should call WakeByAddressSingle to wake a single waiting thread or WakeByAddressAll to wake all waiting threads.

(Added)

More high level synchronization method for this problem is to use condition variable. It is also implemented based on futex. See link

Jangwoong Kim
  • 121
  • 10
  • That s not the equivalent. The problem in my case is the value is unknonwn as it comes from a competitor on the network. This is the reason I need to act on any value change. – user2284570 Jan 02 '21 at 08:59
  • If we cache the previous value and make 1) the server calls FUTEX_WAKE only when the value is modified and 2) the clients calls FUTEX_WAIT for the previous value ,then clients can wake up only when the value is really changed. I modified my answer accordingly. – Jangwoong Kim Jan 02 '21 at 09:41
  • Besides, you need to protect the shared variable. – Jangwoong Kim Jan 02 '21 at 09:43
  • Except the language on the server side doesn t support global variables/symbols and that multiple threads may update it. The fact that the shared variable might change and not protected is on purpose. – user2284570 Jan 02 '21 at 09:45
  • Okay, then clients might miss some price updates :c. Anyway, futex can be used when you want to be notified when the value of an address is changed (like i answered). – Jangwoong Kim Jan 02 '21 at 09:58
  • futex like semaphore seems when chnaged to a specific value, not a value switch. – user2284570 Jan 02 '21 at 15:56
  • That is not true. futex with FUTEX_WAIT operation blocks if the variable equals to the value passed as an argument and unblocks when the they're not equal. If not equal, it immediately returns. So, if you pass the previous price as the argument, then the futex calls will unblock when the price is changed. See [link](https://man7.org/linux/man-pages/man2/futex.2.html). Also see my (modified pseudo-code) answer. – Jangwoong Kim Jan 03 '21 at 16:08
  • More high level method to solve your problem is to use condition variable. It is implemented using futex as well (at least in pthread in glibc implementation). See [pthread condition variable implementation](https://elixir.bootlin.com/glibc/latest/source/nptl/pthread_cond_wait.c) – Jangwoong Kim Jan 03 '21 at 16:14