Just use channels.
I would very surprised if go's net.PacketConn is thread safe, and even
if the default implementation is, we are talking about an interface
here, you cannot rely on that thread safeness for future unknown
implementations of that interface, that some implentations may
implement implicitly on Go.
So, again, to talk to io resources and shared variables, just use
channels:
1) change the direct function call writing on the variable, file or io
for a new function.
2) this function will send the data though a channel.
3) on the other side of the channel there should be a trivial
goroutine composed of a very simple function, this function waits on
the channel and everything that gets there is written to the shared io
or var, and now everything is serialised and atomic.
4) there is only something missing, launching the goroutine passing it
the same channel that the multiple writers will send messages to be
serialised.
You can do something similar for reading and there you might need some
kind of filter to know for which of the potential receivers the
received message is meant.
You should NOT use shared or global variables at all, UNLESS there is
a very good reason for that. And if there is, sometimes a mutex is
simpler than a channel (for bars, not for io most of the time)
And you should not use goroutines just for the sake of it, even though
go ones are really cheap, can have side effects and complicate the
program needlessly. Most of good use good for goroutines are:
- fire and forget, you need to do a task but don't need or want to
wait for it and you don't even need any feedback.
- tell me when done, you need a task to be completed and get some info
from it, but it can be done asynchronously. Here you use a channel
for to send the result back to the initiator.
- subsystems or subapps, or short lived procedures that are
independent, like processing web requests. Or running several
independent apps within a single process.
Jose