fix racy behavior with closing channels

replaces custom channel logic with simpler RWMutex and WaitGroup