Skip to content

Instantly share code, notes, and snippets.

@bebebebebe
Created May 31, 2017 01:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bebebebebe/d9f5c8ac768bcca5d1ff21b0d6c46b96 to your computer and use it in GitHub Desktop.
Save bebebebebe/d9f5c8ac768bcca5d1ff21b0d6c46b96 to your computer and use it in GitHub Desktop.
class HashRace
def initialize
@clients = {}
50.times {add_client}
end
def call
Thread.new do
purge
end
main
end
private
def main
i = 0
loop do
snooze
if rand(2) == 1
k = add_client
puts "new! #{k}"
end
snooze
@clients.each { |key, client|
puts "* #{i} hi #{key}"
}
puts ''
i += 1
end
end
def purge
loop do
snooze
@clients.each { |key, client|
snooze
if rand(10) == 1
puts "* deleting key: #{key}"
@clients.delete(key)
end
}
end
end
def add_client
k = rand_string
v = rand_string
@clients[k] = v
k
end
def rand(n)
[*1..n].sample
end
def snooze
sleep (1.0 / ([*1..5].sample))
end
def rand_string
(0...8).map { ('A'.ord + rand(26)).chr }.join
end
end
t = HashRace.new
t.()
@bebebebebe
Copy link
Author

bebebebebe commented May 31, 2017

This is an example to illustrate a race condition that can occur between two threads. Running it (eventually) leads to an error hash_race.rb:51:in `add_client': can't add a new key into hash during iteration (RuntimeError).

There are two threads: a main thread that occasionally adds a new item ("client") to a hash and iterates over the hash to print out names of clients in the hash; and a purge thread that iterates over the hash of clients and occasionally deletes an element.

The problem occurs when the main thread adds an element to the hash while the purge thread is iterating over it. One way to solve this is by using a mutex, like this.

Here's some sample output:

new! WXQXYLIH
* 0   hi TNXOUYXI
* 0   hi DFELIMPQ
* 0   hi EHVTMZT[
* 0   hi LPWBVNHY
* 0   hi KHW[LNJZ
* 0   hi Z[YSBTEN
* 0   hi ZLPLGCZO
* 0   hi EPDZMQXZ
* 0   hi VUUFWXLK
* 0   hi VWPNDMZY
* 0   hi ICZKJQSG
* 0   hi GMIBUDOV
* 0   hi IKXIXHIX
* 0   hi TMYKRLYQ
* 0   hi [EQSOKWH
* 0   hi TXLVDEXX
* 0   hi ZQZFVOBL
* 0   hi LWMLW[HO
* 0   hi FJOEHDWL
* 0   hi [GHFCYLE
* 0   hi PODIJGMO
* 0   hi ZFC[TLPD
* 0   hi QMCV[FOG
* 0   hi SUYJHSEQ
* 0   hi MIBUTCQH
* 0   hi CKBNINGE
* 0   hi XFLRPDTZ
* 0   hi CZBNEHIO
* 0   hi YFHKXRMM
* 0   hi MZWD[TIJ
* 0   hi CI[UZWSM
* 0   hi ZJSNDTLR
* 0   hi FBGQC[XW
* 0   hi MYHE[UEF
* 0   hi MXBPFRTK
* 0   hi SFWYGWQO
* 0   hi [ZBZVHTI
* 0   hi ILJFHSFI
* 0   hi ESDYPERU
* 0   hi QUFRBV[[
* 0   hi EBHBHKIM
* 0   hi KCZGOVSU
* 0   hi ZXNZTSKI
* 0   hi JFXLDEIZ
* 0   hi [VFKLJNJ
* 0   hi PHYBZVHK
* 0   hi NWPTQBGR
* 0   hi [MYPCYPC
* 0   hi REWZLKWH
* 0   hi KMZERSLO
* 0   hi WXQXYLIH

* deleting key: TNXOUYXI
* 1   hi DFELIMPQ
* 1   hi EHVTMZT[
* 1   hi LPWBVNHY
* 1   hi KHW[LNJZ
* 1   hi Z[YSBTEN
* 1   hi ZLPLGCZO
* 1   hi EPDZMQXZ
* 1   hi VUUFWXLK
* 1   hi VWPNDMZY
* 1   hi ICZKJQSG
* 1   hi GMIBUDOV
* 1   hi IKXIXHIX
* 1   hi TMYKRLYQ
* 1   hi [EQSOKWH
* 1   hi TXLVDEXX
* 1   hi ZQZFVOBL
* 1   hi LWMLW[HO
* 1   hi FJOEHDWL
* 1   hi [GHFCYLE
* 1   hi PODIJGMO
* 1   hi ZFC[TLPD
* 1   hi QMCV[FOG
* 1   hi SUYJHSEQ
* 1   hi MIBUTCQH
* 1   hi CKBNINGE
* 1   hi XFLRPDTZ
* 1   hi CZBNEHIO
* 1   hi YFHKXRMM
* 1   hi MZWD[TIJ
* 1   hi CI[UZWSM
* 1   hi ZJSNDTLR
* 1   hi FBGQC[XW
* 1   hi MYHE[UEF
* 1   hi MXBPFRTK
* 1   hi SFWYGWQO
* 1   hi [ZBZVHTI
* 1   hi ILJFHSFI
* 1   hi ESDYPERU
* 1   hi QUFRBV[[
* 1   hi EBHBHKIM
* 1   hi KCZGOVSU
* 1   hi ZXNZTSKI
* 1   hi JFXLDEIZ
* 1   hi [VFKLJNJ
* 1   hi PHYBZVHK
* 1   hi NWPTQBGR
* 1   hi [MYPCYPC
* 1   hi REWZLKWH
* 1   hi KMZERSLO
* 1   hi WXQXYLIH

hash_race.rb:51:in `add_client': can't add a new key into hash during iteration (RuntimeError)
	from hash_race.rb:23:in `block in main'
	from hash_race.rb:20:in `loop'
	from hash_race.rb:20:in `main'
	from hash_race.rb:13:in `call'
	from hash_race.rb:71:in `<main>'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment