并发地迭代映射并使用RLock/RUnlock进行映射写入。

huangapple go评论111阅读模式
英文:

concurrent map iteration and map write with RLock/RUnlock

问题

不确定为什么我的程序会出现concurrent map iteration and map write错误。我在这里使用了RLock()/mv.RUnlock()

  1. for k := range confirmed_slot {
  2. keys = append(keys, k)
  3. }

这是我完整的Go程序用于测试:

  1. package main
  2. import (
  3. "container/list"
  4. "fmt"
  5. "math/rand"
  6. "sync"
  7. "time"
  8. "github.com/twotwotwo/sorts/sortutil"
  9. )
  10. var (
  11. queue = list.New()
  12. confirmed_slot = map[uint64]string{}
  13. mv sync.RWMutex
  14. )
  15. func FetchConfirmedSlots() {
  16. ticker := time.NewTicker(1 * time.Second)
  17. for {
  18. mv.RLock()
  19. rand.Seed(time.Now().UnixNano())
  20. r := randSeq(10)
  21. slot := rand.Uint64()
  22. confirmed_slot[slot] = r
  23. queue.PushBack(slot)
  24. fmt.Println("Slot Added ", slot, " ", len(confirmed_slot))
  25. mv.RUnlock()
  26. <-ticker.C
  27. }
  28. }
  29. func RemoveItemSlotFull() {
  30. ticker := time.NewTicker(1 * time.Millisecond)
  31. for {
  32. if queue.Len() == 150 {
  33. mv.RLock()
  34. front := queue.Front()
  35. queue.Remove(front)
  36. v, ok := front.Value.(uint64)
  37. if ok {
  38. fmt.Println("Slot deleted ", v)
  39. delete(confirmed_slot, v)
  40. fmt.Println("Slot deleted ", v, " ", len(confirmed_slot))
  41. }
  42. mv.RUnlock()
  43. }
  44. <-ticker.C
  45. }
  46. }
  47. func GetLatestSlot() {
  48. ticker := time.NewTicker(1 * time.Second)
  49. for {
  50. mv.RLock()
  51. if queue.Len() > 0 {
  52. back := queue.Back()
  53. fmt.Println("Slot Fetched ", back.Value, " ", len(confirmed_slot))
  54. }
  55. mv.RUnlock()
  56. <-ticker.C
  57. }
  58. }
  59. func GetConfirmedBlockHashes() {
  60. ticker := time.NewTicker(1 * time.Second)
  61. for {
  62. if queue.Len() > 0 {
  63. mv.RLock()
  64. back := queue.Back()
  65. v, _ := back.Value.(uint64)
  66. keys := make([]uint64, 0, len(confirmed_slot))
  67. for k := range confirmed_slot {
  68. keys = append(keys, k)
  69. }
  70. n := sortutil.SearchUint64s(keys, v)
  71. fmt.Println("Found ... ", n, true)
  72. mv.RUnlock()
  73. }
  74. <-ticker.C
  75. }
  76. }
  77. func main() {
  78. go FetchConfirmedSlots()
  79. go RemoveItemSlotFull()
  80. go GetLatestSlot()
  81. go GetConfirmedBlockHashes()
  82. select {}
  83. }
  84. var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
  85. func randSeq(n int) string {
  86. b := make([]rune, n)
  87. for i := range b {
  88. b[i] = letters[rand.Intn(len(letters))]
  89. }
  90. return string(b)
  91. }
英文:

Not sure why my program is hitting the error of

concurrent map iteration and map write

I have put the RLock()/mv.RUnlock() here

  1. for k := range confirmed_slot {
  2. keys = append(keys, k)
  3. }

Here is my complete go program for test

  1. package main
  2. import (
  3. &quot;container/list&quot;
  4. &quot;fmt&quot;
  5. &quot;math/rand&quot;
  6. &quot;sync&quot;
  7. &quot;time&quot;
  8. &quot;github.com/twotwotwo/sorts/sortutil&quot;
  9. )
  10. var (
  11. queue = list.New()
  12. confirmed_slot = map[uint64]string{}
  13. mv sync.RWMutex
  14. )
  15. func FetchConfirmedSlots() {
  16. ticker := time.NewTicker(1 * time.Second)
  17. for {
  18. mv.RLock()
  19. rand.Seed(time.Now().UnixNano())
  20. r := randSeq(10)
  21. slot := rand.Uint64()
  22. confirmed_slot[slot] = r
  23. queue.PushBack(slot)
  24. fmt.Println(&quot;Slot Added &quot; , slot , &quot; &quot;, len(confirmed_slot))
  25. mv.RUnlock()
  26. &lt;-ticker.C
  27. }
  28. }
  29. func RemoveItemSlotFull() {
  30. ticker := time.NewTicker(1 * time.Millisecond)
  31. for {
  32. if queue.Len() == 150 {
  33. mv.RLock()
  34. front := queue.Front()
  35. queue.Remove(front)
  36. v, ok := front.Value.(uint64)
  37. if ok {
  38. fmt.Println(&quot;Slot deleted &quot; , v)
  39. delete(confirmed_slot, v)
  40. fmt.Println(&quot;Slot deleted &quot; , v , &quot; &quot;, len(confirmed_slot))
  41. }
  42. mv.RUnlock()
  43. }
  44. &lt;-ticker.C
  45. }
  46. }
  47. func GetLatestSlot() {
  48. ticker := time.NewTicker(1 * time.Second)
  49. for {
  50. mv.RLock()
  51. if queue.Len() &gt;0 {
  52. back := queue.Back()
  53. fmt.Println(&quot;Slot Fetched &quot;, back.Value , &quot; &quot;,len(confirmed_slot))
  54. }
  55. mv.RUnlock()
  56. &lt;-ticker.C
  57. }
  58. }
  59. func GetConfirmedBlockHashes() {
  60. ticker := time.NewTicker(1 * time.Second)
  61. for {
  62. if queue.Len() &gt;0 {
  63. mv.RLock()
  64. back := queue.Back()
  65. v, _ := back.Value.(uint64)
  66. keys := make([]uint64, 0, len(confirmed_slot))
  67. for k := range confirmed_slot {
  68. keys = append(keys, k)
  69. }
  70. n := sortutil.SearchUint64s(keys,v)
  71. fmt.Println(&quot;Found ... &quot; , n, true)
  72. mv.RUnlock()
  73. }
  74. &lt;-ticker.C
  75. }
  76. }
  77. func main() {
  78. go FetchConfirmedSlots()
  79. go RemoveItemSlotFull()
  80. go GetLatestSlot()
  81. go GetConfirmedBlockHashes()
  82. select {}
  83. }
  84. var letters = []rune(&quot;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;)
  85. func randSeq(n int) string {
  86. b := make([]rune, n)
  87. for i := range b {
  88. b[i] = letters[rand.Intn(len(letters))]
  89. }
  90. return string(b)
  91. }

答案1

得分: 2

请尝试使用mv.Lock()mv.Unlock()代替mv.RLock()mv.RUnlock()。您正在对confirmed_slot进行写操作。

RLock()RUnlock()用于读取操作-它们允许多个线程同时读取,只要没有线程在写入。

Lock()Unlock()将确保只有一个线程同时持有锁,无论是读取还是写入。

英文:

Instead of mv.RLock() and mv.RUnlock() try mv.Lock() and mv.Unlock(). You are writing to the confirmed_slot.

Rlock() and RUnlock() are for reads - they allow many threads to read at once, as long as none are writing.

Lock() and Unlock() will ensure that only one thread holds the lock at a time, regardless of wheather it is reading or writing.

huangapple
  • 本文由 发表于 2022年3月5日 00:25:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/71354301.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定