Unable to understand a race condition while creating a simple TCP based chat server

Hello community members

I am new to Rust and I have been working on Protohackers problem Budget Chat to get better at concurrency. The gist of the problem is to create a chat server that clients can connect to over TCP.

I've tried my best to use Rust for this but have stumbled into a situation where some clients after a while see memberships as being empty. I've tried using debug lines and a debugger but as this is a concurrency issue I would greatly be thankful to everyone here who could spare some time to help me out.

Here's the link to the playground Rust Playground Please note that my code requires the following crates

anyhow = "1.0.86"
tracing = "0.1"
tracing-subscriber = "0.3"
regex = "1"

I obviously can't tell where the issue is hiding at a glance, but what I can tell is that this sort of design is smelly.
On one hand, everything has access to shared state, but at the same time you some vestiges of event-driven architecture. My suggestion would be to throw out shared state and mutexes entirely, and make use of channels instead.

1 Like

write -> write_all is only obvious change.

It locks everything for writes. Don't see from just read through what would give what you describe.

Thanks for suggesting this. I gave that a shot and it did not make any difference in the behavior.

The code looks fine. You don't have unsafe code and I don't see anything that could cause a deadlock, so it must not be a lock-related concurrency issue. So it has to be some sort of protocol-related issue.

I noticed that there is no check for a client that connects with a name that is already in use. Could the test be causing this to happen? It may be worth checking to see if this happens using debugging code. And of course the connection should be closed when it is detected.

Note that HashMap.insert will overwrite an existing entry with the given key.