std::atomic_signal_fence() Establishes memory synchronization ordering ... between a thread and a signal handler executed on the same thread. -- cppreference
-
In order to find an example for this illustration, I looked at bames53's similar question in stackoverflow. However the answer may not suit my x86_64 environment, since x86_64 CPU is strong memory model and forbids Store-Store re-ordering ^1. Its example will correctly execute even without
std::atomic_signal_fence()
in my x86_64 environment. -
So I made a Store-Load re-ordering example suitable for x86_64 after Jeff Preshing's post. The example code is not that short, so I opened this question instead of appending onto bames53's similar question.
#include <atomic>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <semaphore.h>
#include <signal.h>
#include <unistd.h>
sem_t endSema;
// volatile int synchronizer;
int X, Y;
int r1, r2;
void signal_handler(int sig) {
signal(sig, SIG_IGN);
Y = 1;
// std::atomic_signal_fence(std::memory_order_seq_cst); // if uncommented, assert still may fail
r2 = X;
signal(SIGINT, signal_handler);
sem_post(&endSema); // if changed to the following, assert never fail
// synchronizer = 1;
}
int main(int argc, char* argv[]) {
std::srand(std::time(nullptr));
sem_init(&endSema, 0, 0);
signal(SIGINT, signal_handler);
for (;;) {
while(std::rand() % std::stol(argv[1]) != 0); // argv[1] ~ 1000'000
X = 1;
// std::atomic_signal_fence(std::memory_order_seq_cst); // if uncommented, assert still may fail.
r1 = Y;
sem_wait(&endSema); // if changed to the following, assert never fail
// while (synchronizer == 0); synchronizer = 0;
std::cout << "r1=" << r1 << " r2=" << r2 << std::endl;
if (r1 == 0) assert(r2 != 0);
Y = 0; r1 = 0; r2 = 0; X = 0;
}
return 0;
}
-
Firstly semaphore is used to synchronize main() with signal_handler(). In this version, the assert always fail after around received 30 SIGINTs with or without the signal fence. It seems that
std::atomic_signal_fence()
did not work as I expected. -
Secondly If semaphore is replaced with
volatile int synchronizer
, the program seems never fail with or without the signal fence.
What's wrong with the code? Or did I miss-understand the cppreference doc?
Below is some relevant info:
-
compiling & running env: CentOS 8 (Linux 4.18.0) x86_64 single CPU core.
-
Compiler: g++ (GCC) 8.3.1 20190507
-
Compiling command
g++ -std=c++17 -o ordering -O2 ordering.cpp -pthread
-
Run with
./ordering 1000000
, then keep pressing Ctrl-C to invoke the signal handler.
Aucun commentaire:
Enregistrer un commentaire