在golang中,如何保护自己的锁安全装置不受调用者破坏?

I try use "sync.mutex" protect my func,but i found that the lock still uses the caller to destroy it.

var mutex sync.mutex

This is error:

//caller use
func a() {
    for i := 0; i < 10; i++ {
        go b(i)
    }
}

//My func
func b(i int) {
    mutex.Lock()
    fmt.Println(i)
    mutex.Unlock()
}

this is success,but destroyed my encapsulation method:

//caller use
func a() {
    for i := 0; i < 10; i++ {
        mutex.Lock()
        go b(i)
    }
}

//my func
func b(i int) {
    fmt.Println(i)
    mutex.Unlock()
}

Thanks

The Go Programming Language Specification

Exported identifiers

An identifier may be exported to permit access to it from another package. An identifier is exported if both:

  • the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
  • the identifier is declared in the package block or it is a field name or method name.

All other identifiers are not exported.

Put the function in its own package and don't export the mutex. For example.

package b

import (
    "fmt"
    "sync"
)

var mutex sync.Mutex

func B(i int) {
    mutex.Lock()
    fmt.Println(i)
    mutex.Unlock()
}

To use,

package a

import "b"

func a() {
    for i := 0; i < 10; i++ {
        go b.B(i)
    }
}

In the first example, all the calls to go b(i) are called in a's loop, but the loop can be finished before any of the goroutines have a chance to start, so if main returns, then all those goroutines stop.

In the second example, the mutex locks and doesn't unlock until Unlock is called in each of the b goroutines. The result is that the calls are completely sequential since each iteration of the loop in a can't start until the last iteration's b goroutine finishes and calls Unlock.

A better practice in Go would be for your b function to take in a pointer to the mutex along with the number passed in, so in your original example it would look like:

//caller use
func a() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            b(&mutex, i)
        }()
    }
    wg.Wait()
}

//My func
func b(mutex *sync.Mutex, i int) {
    mutex.Lock()
    fmt.Println(i)
    mutex.Unlock()
}

Which would remove reliance on a global variable and also guarantee that all calls to b are using the exact same mutex since we pass in a pointer to one mutex