I have seen reference to using ring buffers, and controlled access the location pointers to eliminate or reduce the need for locks. It does not eliminate the need for waits though, and should only work then a ring buffer has one writer and one reader. In your case you would need at least two buffers.
The mechanism as I understand it is:
Depending on the wait time used this can either add latency for new items in an empty queue, or burn a lot of CPU cycles in the wait loop. The order of updating the pointer and strict separation of write access is critical for this to work. The writer is only allowed to write the ring buffer entry before incrementing the pointer to make it available to the reader.