从带锁的地图读取不会通过通道返回值

I tried to implement a locking version of reading/writing from a map in golang, but it doesn't return the desired result.

package main

import (
    "sync"
    "fmt"
)

var m = map[int]string{}
var lock = sync.RWMutex{}

func StoreUrl(id int, url string) {
        for {
                lock.Lock()
                defer lock.Unlock()

                m[id] = url
        }
}

func LoadUrl(id int, ch chan string) {
    for {
        lock.RLock()
        defer lock.RUnlock()

        r := m[id]
        ch <- r
    }
}

func main() {
    go StoreUrl(125, "www.google.com")

    chb := make(chan string)
    go LoadUrl(125, chb);

    C := <-chb
    fmt.Println("Result:", C)                           
}

The output is:

Result: 

Meaning the value is not returned via the channel, which I don't get. Without the locking/goroutines it seems to work fine. What did I do wrong?

The code can also be found here:

https://play.golang.org/p/-WmRcMty5B

Infinite loops without sleep or some kind of IO are always bad idea.

In your code if you put a print statement at the start of StoreUrl, you will find that it never gets printed i.e the go routine was never started, the go call is setting putting the info about this new go routine in some run queue of the go scheduler but the scheduler hasn't ran yet to schedule that task. How do you run the scheduler? Do sleep/IO/channel reading/writing.

Another problem is that your infinite loop is taking lock and trying to take the lock again, which will cause it to deadlock. Defer only run after function exit and that function will never exit because of infinite loop.

Below is modified code that uses sleep to make sure every execution thread gets time to do its job.

package main

import (
    "sync"
    "fmt"
    "time"
)

var m = map[int]string{}
var lock = sync.RWMutex{}

func StoreUrl(id int, url string) {
        for {
                lock.Lock()
                m[id] = url
                lock.Unlock()
                time.Sleep(1)
        }
}

func LoadUrl(id int, ch chan string) {
    for {
            lock.RLock()
            r := m[id]
            lock.RUnlock()
            ch <- r

    }
}

func main() {
    go StoreUrl(125, "www.google.com")
    time.Sleep(1)
    chb := make(chan string)
    go LoadUrl(125, chb);

    C := <-chb
    fmt.Println("Result:", C)
}

Edit: As @Jaun mentioned in the comment, you can also use runtime.Gosched() instead of sleep.

Usage of defer incorrect, defer execute at end of function, not for statement.

func StoreUrl(id int, url string) {
    for {
        func() {
            lock.Lock()
            defer lock.Unlock()
            m[id] = url
        }()
    }
}

or

func StoreUrl(id int, url string) {
    for {
        lock.Lock()
        m[id] = url
        lock.Unlock()
    }
}

We can't control the order of go routine, so add time.Sleep() to control the order.

code here:

https://play.golang.org/p/Bu8Lo46SA2