I unfortunately cannot think of any portable possibility. The problem is the fact that you try to read from the stream and that reading cannot be timed out or wakened - in standard c++ (or standard c).
What is possible though is to use the non portable select. With select you can listen for more than just one file descriptor. You can then create a pipe (also non portable) and add the read end of the pipe to the file descriptors you're listening on. That way you can wake up the thread that listens on stdin.
Maybe it's a better solution to go for the alternative mentioned in the comments, that way you just have to wait for the complete input but that might not be an issue, since you can evaluate whether the answer was provided in the given time slot or not. That way you could use portable c++.
The non portable solution could look like this:
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
#ifdef WIN32
#    include <io.h>
#    include <winsock2.h>
#else
#    include <sys/select.h>
#    include <unistd.h>
#endif
using namespace std::chrono_literals;
struct Quiz
{
    int pipe[2];
};
void countDown (const Quiz& quiz)
{
    std::this_thread::sleep_for (5s);
    std::cout << "Notify quiz...\n";
    char trigger {'s'};
#ifdef WIN32
    _write (quiz.pipe[1], &trigger, sizeof trigger);
#else
    write (quiz.pipe[1], &trigger, sizeof trigger);
#endif
}
void quiz (const Quiz& quiz)
{
    while (true) {
        fd_set fds;
        FD_ZERO (&fds);
        FD_SET (0, &fds);
        FD_SET (quiz.pipe[0], &fds);
        std::cout << "some question?\n";
        int result = select (quiz.pipe[0] + 1, &fds, nullptr, nullptr, nullptr);
        if (result < 0) {
            std::cerr << "Uh oh, problem in select\n";
            return;
        }
        if (FD_ISSET (quiz.pipe[0], &fds)) {
            std::cout << "time's up\n";
            return;
        }
        else {
            std::string answer;
            std::cin >> answer;
            std::cout << "your answer: " << answer << '\n';
        }
    }
    std::cout << "time's up\n";
}
int main ()
{
    Quiz bucket;
#ifdef WIN32
    _pipe (quiz.pipe, 256, O_BINARY);
#else
    pipe (bucket.pipe);
#endif
    std::thread th1 {&countDown, std::cref (bucket)};
    std::thread th2 {&quiz, std::cref (bucket)};
    std::cout << "both threads have started\n";
    th1.join ();
    th2.join ();
    std::cout << "both threads have ended\n";
#ifdef WIN32
    _close (quiz.pipe[1]);
    _close (quiz.pipe[0]);
#else
    close (bucket.pipe[1]);
    close (bucket.pipe[0]);
#endif
}
I want to mention that I changed the plain bool to an atomic boolean in order to eliminate possible race conditions.