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

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

concurrent map iteration and map write with RLock/RUnlock

问题

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

for k := range confirmed_slot {
    keys = append(keys, k)
}

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

package main

import (
	"container/list"
	"fmt"
	"math/rand"
	"sync"
	"time"
	"github.com/twotwotwo/sorts/sortutil"
)

var (
	queue          = list.New()
	confirmed_slot = map[uint64]string{}
	mv sync.RWMutex
)

func FetchConfirmedSlots() {
	ticker := time.NewTicker(1 * time.Second)
	for {
		mv.RLock()
		rand.Seed(time.Now().UnixNano())
		r := randSeq(10)
		slot := rand.Uint64()
		confirmed_slot[slot] = r
		queue.PushBack(slot)
		fmt.Println("Slot Added ", slot, "  ", len(confirmed_slot))
		mv.RUnlock()
		<-ticker.C
	}
}

func RemoveItemSlotFull() {
	ticker := time.NewTicker(1 * time.Millisecond)
	for {
		if queue.Len() == 150 {
			mv.RLock()
			front := queue.Front()
			queue.Remove(front)
			v, ok := front.Value.(uint64)
			if ok {
				fmt.Println("Slot deleted ", v)
				delete(confirmed_slot, v)
				fmt.Println("Slot deleted ", v, "  ", len(confirmed_slot))
			}
			mv.RUnlock()

		}
		<-ticker.C
	}
}

func GetLatestSlot() {
	ticker := time.NewTicker(1 * time.Second)
	for {
		mv.RLock()
		if queue.Len() > 0 {
			back := queue.Back()
			fmt.Println("Slot Fetched ", back.Value, " ", len(confirmed_slot))
		}
		mv.RUnlock()
		<-ticker.C
	}
}

func GetConfirmedBlockHashes() {
	ticker := time.NewTicker(1 * time.Second)
	for {
		if queue.Len() > 0 {
			mv.RLock()
			back := queue.Back()
			v, _ := back.Value.(uint64)
			keys := make([]uint64, 0, len(confirmed_slot))

			for k := range confirmed_slot {
				keys = append(keys, k)
			}

			n := sortutil.SearchUint64s(keys, v)
			fmt.Println("Found ... ", n, true)
			mv.RUnlock()

		}
		<-ticker.C
	}

}

func main() {

	go FetchConfirmedSlots()
	go RemoveItemSlotFull()
	go GetLatestSlot()

	go GetConfirmedBlockHashes()
	select {}

}

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func randSeq(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}
英文:

Not sure why my program is hitting the error of

concurrent map iteration and map write

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

for k := range confirmed_slot {
keys = append(keys, k)
}

Here is my complete go program for test

package main

import (
	&quot;container/list&quot;
	&quot;fmt&quot;
	&quot;math/rand&quot;
	&quot;sync&quot;
	&quot;time&quot;
	&quot;github.com/twotwotwo/sorts/sortutil&quot;
)

var (
	queue          = list.New()
	confirmed_slot = map[uint64]string{}
	mv sync.RWMutex
)

func FetchConfirmedSlots() {
	ticker := time.NewTicker(1 * time.Second)
	for {
		mv.RLock()
		rand.Seed(time.Now().UnixNano())
		r := randSeq(10)
		slot := rand.Uint64()
		confirmed_slot[slot] = r
		queue.PushBack(slot)
		fmt.Println(&quot;Slot Added &quot; , slot , &quot;  &quot;, len(confirmed_slot))
		mv.RUnlock()
		&lt;-ticker.C
	}
}

func RemoveItemSlotFull() {
	ticker := time.NewTicker(1 * time.Millisecond)
	for {
		if queue.Len() == 150 {
			mv.RLock()
			front := queue.Front()
			queue.Remove(front)
			v, ok := front.Value.(uint64)
			if ok {
				fmt.Println(&quot;Slot deleted &quot; , v)
				delete(confirmed_slot, v)
				fmt.Println(&quot;Slot deleted &quot; , v , &quot;  &quot;, len(confirmed_slot))
			}
			mv.RUnlock()

		}
		&lt;-ticker.C
	}
}

func GetLatestSlot() {
	ticker := time.NewTicker(1 * time.Second)
	for {
		mv.RLock()
		if queue.Len() &gt;0  {
			back := queue.Back()
			fmt.Println(&quot;Slot Fetched &quot;, back.Value , &quot; &quot;,len(confirmed_slot))
		}
		mv.RUnlock()
		&lt;-ticker.C
	}
}

func GetConfirmedBlockHashes() {
	ticker := time.NewTicker(1 * time.Second)
	for {
		if queue.Len() &gt;0  {
			mv.RLock()
			back := queue.Back()
			v, _ := back.Value.(uint64)
			keys := make([]uint64, 0, len(confirmed_slot))


			for k := range confirmed_slot {
				keys = append(keys, k)
			}


			n := sortutil.SearchUint64s(keys,v)
			fmt.Println(&quot;Found ... &quot; , n, true)
			mv.RUnlock()

		}
		&lt;-ticker.C
	}

}


func main() {

	go FetchConfirmedSlots()
	go RemoveItemSlotFull()
	go GetLatestSlot()

	go GetConfirmedBlockHashes()
	select {}

}

var letters = []rune(&quot;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;)

func randSeq(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

答案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:

确定