Search code examples
c++vectorposixsignal-handlingasync-safe

Is read-only access to a vector (vector::operator[] and vector::size()) asynchronous-safe?


My program needs to perform read-only access to the contents of a vector<string> in a signal handler for SIGINT. (The alternative is to use a fixed-size array of fixed-length C strings.) The program is designed to run in a POSIX environment.

Are vector::operator[] and vector::size() asynchronous-safe (or signal-safe)?


Solution

  • Angew's answer is correct considering C++. Now that the question mentions POSIX environment, which could provide stronger guarantees, this needs another answer, which is:

    If the process is multi-threaded, or if the process is single-threaded and a signal handler is executed other than as the result of:

    • The process calling abort(), raise(), kill(), pthread_kill(), or sigqueue() to generate a signal that is not blocked

    • A pending signal being unblocked and being delivered before the call that unblocked it returns

    the behavior is undefined if the signal handler refers to any object other than errno with static storage duration other than by assigning a value to an object declared as volatile sig_atomic_t, or if the signal handler calls any function defined in this standard other than one of the functions listed in the following table.

    Source: The Open Group Base Specifications Issue 7 IEEE Std 1003.1, 2013 Edition, 2.4.3

    This is... still a very weak guarantee. As far as I can understand this:

    vector::operator[] is not safe. Fixed arrays are not safe. Access to fixed arrays is safe if the array is non-static.

    Why? vector::operator[] doesn't specify exactly how it should be implemented, only the preconditions and postconditions. The access to elements of an array is possible (if the array is non-static), this implies that the access to vector elements is also safe if you create a pointer (with vec.data() or &vec[0]) before signalling, and then accessing the elements through the pointer.

    EDIT: Originally I missed that because I wasn't aware of the sigaction function - with signal you could only access your local arrays in the signal handler, but with sigaction you can provide pointers to automatic and dynamically arrays. The advice with doing as little as possible in signal handlers still applies here though.

    Bottom line: You're doing too much in your signal handlers. Try doing as little as possible. One approach is to assign to a flag (of type volatile sig_atomic_t), and return. The code can later check if the flag was triggered (e.g. in an event loop)