TChan
operations are performed when a transaction is committed, just like other STM operations, so you'll always end up with a single write, no matter how many times your transaction is retried. They'd be kind of useless otherwise.
To convince yourself, try this example:
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TChan
main = do
ch <- atomically newTChan
forkIO $ reader ch >>= putStrLn
writer ch
reader = atomically . readTChan
writer ch = atomically $ writeTChan ch "hi!" >> retry
This will throw a exception complaining that the transaction is blocked indefinitely. If writeTChan
caused a write to happen before the transaction was committed, the program would print "hi!" before throwing that exception.