如何在更改地图数据时防止死锁发生

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

How to prevent deadlock when change map data

问题

我尝试编写一个验证数据的函数。请看下面的代码:

func Create(name, email, password, local string, termOf bool) map[string]string {

    wait := new(sync.WaitGroup)
    mutex := new(sync.Mutex)
    errMsg := make(map[string]string)

    if !termOf {
        mutex.Lock()
        errMsg["termOf"] = translate(local, "text06")
        mutex.Unlock()
    }

    wait.Add(1)
    go func() {
        err := ValidateName(name, local)
        mutex.Lock()
        errMsg["name"] = err.Error()
        mutex.Unlock()
        wait.Done()
    }()

    wait.Add(1)
    go func() {
        err := ValidateEmail(email, local)
        mutex.Lock()
        errMsg["email"] = err.Error()
        mutex.Unlock()
        wait.Done()
    }()

    wait.Add(1)
    go func() {
        err := ValidatePassword(password, local)
        mutex.Lock()
        errMsg["password"] = err.Error()
        mutex.Unlock()
        wait.Done()
    }()

    wait.Wait()

    // 如果出现错误
    if len(errMsg) > 0 {
        return errMsg
    }

    return nil
}

正如你在这里看到的,我使用了三个 goroutine,在 goroutine 中我锁定它以更改 errMsg 变量的 map 类型。当我运行该函数时,我得到了编译器错误:

runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x14 pc=0x44206a]

但是当我在 goroutine 中删除所有的 errMsg 插入时,函数就可以正常工作。我不知道我做错了什么原因。

英文:

I try to write a function that validate data. Look at the following code:

func Create(name, email, password, local string, termOf bool) map[string]string {

	wait := new(sync.WaitGroup)
	mutex := new(sync.Mutex)
	errMsg := make(map[string]string)

	if !termOf {
		mutex.Lock()
		errMsg["termOf"] = translate(local, "text06")
		mutex.Unlock()
	}

	wait.Add(1)
	go func() {
		err := ValidateName(name, local)
		mutex.Lock()
		errMsg["name"] = err.Error()
		mutex.Unlock()
		wait.Done()
	}()

	wait.Add(1)
	go func() {
		err := ValidateEmail(email, local)
		mutex.Lock()
		errMsg["email"] = err.Error()
		mutex.Unlock()
		wait.Done()
	}()

	wait.Add(1)
	go func() {
		err := ValidatePassword(password, local)
		mutex.Lock()
		errMsg["password"] = err.Error()
		mutex.Unlock()
		wait.Done()
	}()

	wait.Wait()

	// If errors appear
	if len(errMsg) > 0 {
		return errMsg
	}

	return nil
}

As you can see here, I use three goroutines and in the goroutine I lock it to change errMsg variable map type. When I run the function, I've got compiler error

runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x14 pc=0x44206a]

But when I remove in the goroutine all errMsg inserts, then the function works. I do not know the reason what I do wrong.

答案1

得分: 3

ValidateName()ValidateEmail()ValidatePassword()调用返回时,err可能是nil

在将其添加到映射之前,应检查err != nil

if err != nil {
    mutex.Lock()
    errMsg["xxx"] = err.Error()
    mutex.Unlock()
}

换句话说,问题不在于映射errMsg,而在于您想要放入其中的值。

英文:

It is possible that err is nil when returning from ValidateName(), ValidateEmail() or ValidatePassword() calls.

You should check err != nil before adding it to the map.

if err != nil {
    mutex.Lock()
    errMsg["xxx"] = err.Error()
    mutex.Unlock()
}

In other words, this isn't the map errMsg which is the issue, but the value you want to put in it.

huangapple
  • 本文由 发表于 2014年9月9日 21:02:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/25745374.html
匿名

发表评论

匿名网友

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

确定