def spawn_reader_writer(get_data_fn, put_data_fn):
    """Spawn a thread that reads from a data source and writes to a sink.

    The thread will terminate if it receives a Falsey value from the source.

    Args:
        get_data_fn: Data-reading function. Called repeatedly until it returns
            False-y to indicate that the thread should terminate.
        put_data_fn: Data-writing function.
    Returns: threading.Thread
    """
    def _reader_thread():
        while True:
            out = get_data_fn()
            put_data_fn(out)
            if not out:
                # EOF.
                # We've passed this on so things farther down the pipeline will
                # know to shut down.
                break

    t = threading.Thread(target=_reader_thread)
    t.daemon = True
    t.start()
    return t
Spawn a thread that reads from a data source and writes to a sink.

    The thread will terminate if it receives a Falsey value from the source.

    Args:
        get_data_fn: Data-reading function. Called repeatedly until it returns
            False-y to indicate that the thread should terminate.
        put_data_fn: Data-writing function.
    Returns: threading.Thread