The top level map locks doesn’t matter - it is write once at init and read only after.
> On Feb 22, 2022, at 11:51 PM, Jason E. Aten <[email protected]> wrote: > > You have not synchronized access to the top level mapLocks map itself. Thus > you will get races. You need to have a mutex that you lock before you access > mapLocks; not just the maps that are inside it. > > I would also recommend being a little object oriented about this design, > putting each map inside its own struct, and make a set of accessor methods > that Lock() and defer Unlock() on a mutex that protects the maps inside. > Read code like this for an idea of what I mean. > https://github.com/glycerine/atomicmap/blob/master/amap.go > >> On Tuesday, February 22, 2022 at 9:55:04 PM UTC-6 [email protected] wrote: >> Something else is wrong - because marketMaps is read-only after init… so >> unless you have some other code - that is not the map causing the panic. >> >> My guess is because you are returning the map from ReadMaps (or RWMaps) that >> you are using THAT map by multiple threads outside the lock (the map is a >> reference not a copy) and that is causing the panic. >> >>>> On Feb 22, 2022, at 9:39 PM, Zhaoxun Yan <[email protected]> wrote: >>>> >>> Hi guys! >>> I know this is quite challenging, but it makes sense in io-heavy >>> applications. >>> >>> I need to test the responsiveness of different financial future quotation >>> sources. They return the quotations spontaneously, and my program respond >>> to each one of the CGO call backs from the quotation library and save the >>> current prices. Meanwhile, a timer ensures to check the current quotations >>> of each available sources. And obviously, it raised up a panic due to >>> synchronization of maps on the call of ReadMaps function. Unfortunately >>> this came up occasionally and `go build -race` cannot raise the problem. >>> >>> Here is a piece of the code, only the read/write part: >>> >>> ------------------------------------------------------------------------------------------ >>> >>> // Please Ignore SyChan to alert the timer that all available sources are >>> collected >>> var SyChan chan int = make(chan int, 3) >>> >>> // Make up a map of 5 mutex locks and a map of 5 data structs, indexed by >>> 1-5 >>> var marketMaps = make(map[int]map[string]Market) >>> var mapLocks = make(map[int]*sync.Mutex) >>> >>> // quotation data >>> type Market struct { >>> Price float64 `json:"price"` >>> Timestamp string `json:"timestamp"` >>> } >>> >>> func init() { >>> for i := 1; i <= 5; i++ { >>> mapLocks[i] = new(sync.Mutex) >>> marketMaps[i] = make(map[string]Market) >>> } >>> } >>> >>> //Make sure that for each source, R/W has no race, only took place as >>> acquiring the particular Mutex inside the map of Mutex. >>> func RWMaps(targetnum int, purpose, future_id string, market Market) >>> map[string]Market { >>> >>> mapLocks[targetnum].Lock() >>> defer mapLocks[targetnum].Unlock() >>> >>> if purpose == "update" {//The original Write part >>> marketMaps[targetnum][future_id] = market >>> return nil >>> } else { //The read part, has been extracted to ReadMaps >>> SyChan <- 1 >>> return marketMaps[targetnum] >>> } >>> } >>> >>> //Here is why I use map: not all 5 sources must be available, some may have >>> connection failure and would be marked as false in Usable[i] , i being its >>> source No. >>> func ReadMaps(targetnum, checkTime int) map[string]Market { >>> mapLocks[targetnum].Lock() >>> defer mapLocks[targetnum].Unlock() >>> if Usable[targetnum] { >>> fmt.Printf("%d-th time to read source %d \n", checkTime, >>> targetnum) >>> } >>> SyChan <- 1 >>> return marketMaps[targetnum] >>> } >>> >>> -------------------------------------------------------------------------------------------------- >>> >>> My problem is : >>> >>> I still want to keep the map structure, rather than naming mutex1, mutex2, >>> mutex3,... , marketmsg1, marketmsg2, .... And obviously if the map >>> prohibits reading or writing spontaneously, the writing by each usable >>> sources is not fair - They must line up as one queue (like using one Mutex >>> for all instead) hence the checking of quotation snap on a time-spot is >>> defected. I have also checked the sync.Map and it seems to allow >>> spontaneous reading but still prohibits spontaneous writing. >>> >>> My instinct is to make map on the pointer of structs. On that way, if I >>> could use sync.Map, both the read and write function only read the map to >>> find the address of data structs, then writing several data structs on the >>> same time won't violate the rule on sync.Map. >>> >>> Is the proposal above legitimate? And anyone could come up a test case to >>> mimic the quotation sources? Because with CGO to complicate the program, go >>> cannot raise the race problem on -race check, and the successful build can >>> panic occasionally. >>> >>> Thanks in advance! >>> >> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "golang-nuts" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to [email protected]. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/golang-nuts/9a981200-23f8-4dae-8c20-7acfdcd3f2fcn%40googlegroups.com. >> > > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/215a541a-ecc6-49e2-9427-81f62c5b168en%40googlegroups.com. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/87176801-8735-4312-BBD4-42AF49979F1C%40ix.netcom.com.
