simpler implementation without threaded state