An answer that is presumably cross platform, by abusing the asyncio
module.
I don't fully understand what I did, and I am sure it is bad form, but I've created two concurrent tasks, one that waits for input, and one that checks the queue for a value and raises an InterruptError. Because of the return_when='FIRST_EXCEPTION' setting, it was necessary for both functions to raise an exception. I returned the user input via the exception, since the function never returns.
import asyncio
import multiprocessing
import time
from aioconsole import ainput
def my_function(queue):
time.sleep(3)
queue.put(5)
async def my_loop(queue):
while True:
await asyncio.sleep(0.1)
if not queue.empty():
raise InterruptedError
async def my_exceptional_input():
text = await ainput("Enter input:")
raise InterruptedError(text)
async def main():
queue = multiprocessing.Queue()
p = multiprocessing.Process(target=my_function, args=(queue,))
p.start()
task1 = asyncio.create_task(my_exceptional_input())
task2 = asyncio.create_task(my_loop(queue))
result = await asyncio.wait([task1, task2], return_when='FIRST_EXCEPTION')
try:
task2.result()
except asyncio.exceptions.InvalidStateError:
text = str(task1.exception())
except InterruptedError:
text = ""
print('Doing stuff with input %s...' % text)
if __name__ == '__main__':
asyncio.run(main())
EDIT: It was silly of me to use 'FIRST_EXCEPTION'. I could have used 'FIRST_COMPLETED' like this:
import asyncio
import multiprocessing
import time
from aioconsole import ainput
def my_function(queue):
time.sleep(3)
queue.put(5)
async def my_loop(queue):
while True:
await asyncio.sleep(0.1)
if not queue.empty():
break
async def main():
queue = multiprocessing.Queue()
p = multiprocessing.Process(target=my_function, args=(queue,))
p.start()
task1 = asyncio.create_task(ainput("Enter text:"))
task2 = asyncio.create_task(my_loop(queue))
result = await asyncio.wait([task1, task2], return_when='FIRST_COMPLETED')
try:
text = task1.result()
q = ""
except asyncio.exceptions.InvalidStateError:
text = ""
q = queue.get()
print('Doing stuff with input %s/%s...' % (text, q))
if __name__ == '__main__':
asyncio.run(main())