std::atomic<pid_t> expected_pid;
    const int sig = SIGRTMIN;
    std::atomic<int> sequence_num = 0;    
    std::atomic<int> data_ready_num = 0;
    std::atomic<bool> signal_latch = false;   
    /** Notes:
      * Only one query from the table can be processed at the moment of time.
      * This is ensured by the mutex in fillData function.
      * We obtain information about threads by sending signal and receiving info from the signal handler.
      * Information is passed via global variables and pipe is used for signaling.
      * Actually we can send all information via pipe, but we read from it with timeout just in case,
      * so it's convenient to use is only for signaling.
      */
    StackTrace stack_trace{NoCapture{}};
    constexpr size_t max_query_id_size = 128;
    char query_id_data[max_query_id_size];
    size_t query_id_size = 0;
    LazyPipeFDs notification_pipe;
    void signalHandler(int, siginfo_t * info, void * context)
    {
        DENY_ALLOCATIONS_IN_SCOPE;
        auto saved_errno = errno;   
        
        
        if (info->si_pid != expected_pid)
            return;
        
        int notification_num = info->si_value.sival_int;
        if (notification_num != sequence_num.load(std::memory_order_acquire))