MST

星途 面试题库

面试题:Go语言Goroutine资源清理与并发安全

有一个Goroutine在运行过程中打开了多个文件描述符用于读写操作,同时它会和其他Goroutine共享一些数据。当该Goroutine需要优雅退出时,既要保证文件描述符正确关闭以避免资源泄漏,又要确保共享数据的并发安全。请详细阐述实现方案并编写相应代码。
21.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

实现方案

  1. 文件描述符关闭:使用defer关键字来确保在Goroutine结束时关闭所有打开的文件描述符。defer语句会在函数返回时按照后进先出(LIFO)的顺序执行,这样可以保证文件描述符在函数结束时被正确关闭。
  2. 共享数据并发安全:使用sync.Mutex来保护共享数据。在访问共享数据之前,先获取锁,访问结束后释放锁,从而避免竞态条件。

代码示例

package main

import (
    "fmt"
    "io/ioutil"
    "sync"
)

// 定义共享数据结构
type SharedData struct {
    data int
    mu   sync.Mutex
}

// Goroutine函数
func worker(shared *SharedData, filePaths []string, wg *sync.WaitGroup) {
    defer wg.Done()

    // 打开文件描述符
    var files []*ioutil.File
    for _, filePath := range filePaths {
        file, err := ioutil.TempFile("", filePath)
        if err != nil {
            fmt.Printf("Failed to open file %s: %v\n", filePath, err)
            return
        }
        files = append(files, file)
    }
    defer func() {
        for _, file := range files {
            file.Close()
        }
    }()

    // 操作共享数据
    shared.mu.Lock()
    shared.data++
    shared.mu.Unlock()

    // 模拟一些工作
    fmt.Println("Worker is doing some work...")
}

func main() {
    shared := &SharedData{}
    filePaths := []string{"file1.txt", "file2.txt"}
    var wg sync.WaitGroup
    wg.Add(1)

    go worker(shared, filePaths, &wg)
    wg.Wait()

    fmt.Printf("Final shared data: %d\n", shared.data)
}

在上述代码中:

  1. SharedData结构体包含一个整数类型的数据data和一个sync.Mutex类型的锁mu,用于保护data的并发访问。
  2. worker函数接收共享数据指针、文件路径切片和sync.WaitGroup指针。在函数内部,使用defer来关闭打开的文件描述符,并通过锁来确保共享数据的并发安全。
  3. main函数启动一个Goroutine并等待它完成,最后打印共享数据的最终值。