Нужен ли мьютекс при замене значения строки в разных горутинах?

Нужен ли в этом случае мьютекс? Я обновляю токен с помощью горутины, токен используется в другой горутине. Другими словами, будет ли мой токен в какой-то момент пустым, чтобы ответом был 401?

Если да, то это часть структуры c *threatq или это простая переменная, я имею в виду «автономную» внутри моего кода.

// IndicatorChannelIterator returns indicators from ThreatQ into a channel.
func (c *threatq) IndicatorChannelIterator() (<-chan *models.Indicator, error) {
    // Authenticate
    token, err := c.authenticate(c.clientID, c.email, c.password)
    if err != nil {
        return nil, fmt.Errorf("Error while authenticating to TQ : %s", err)
    }

    // Periodically refresh the token
    ticker := time.NewTicker(30 * time.Minute)
    go func() {
        for range ticker.C {
            token, err = c.authenticate(c.clientID, c.email, c.password)
            if err != nil {
                logrus.Errorf("Error while authenticating to TQ : %s", err)
            }
        }
    }()

    // Prepare the query
    query := &Query{}

    // Get the first page
    firstTQResponse, err := c.advancedSearch(query, token, 0)
    if err != nil {
        return nil, fmt.Errorf("Error while getting the first page from TQ : %s", err)
    }

    // Create the channel
    indicators := make(chan *models.Indicator)

    // Request the others
    go func() {
        req := 1
        total := firstTQResponse.Total
        for offset := 0; offset < total; offset += c.perPage {    
            // Search the indicators
            tqResponse, err := c.advancedSearch(query, token, offset)
            if err != nil {
                logrus.Errorf("Error while getting the indicators from TQ : %s", err)
                continue
            }

...

Конечно. Но если сомневаетесь: запустите его под детектором гонки.

Volker 22.05.2019 12:18
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
1
883
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Да, вы также можете попробовать запустить этот тест с включенным флагом -race. Детектор гонки Go, вероятно, скажет вам, что токен является общей переменной для нескольких горутин. Таким образом, он должен быть защищен с помощью Mutex или RWMutex.

В вашем случае я думаю, что RWMutex более подходит, потому что есть одна горутина, которая изменяет (то есть записывает) состояние token каждые 30 минут, а другая горутина считывает его значение.

Если вы не защитите общую переменную блокировкой, вторая горутина может прочитать старое значение token, срок действия которого может быть просрочен.

Ответ принят как подходящий

Правило простое: если к переменной обращаются из нескольких горутин и хотя бы одна из них является записью, необходима явная синхронизация.

В вашем случае так: одна ваша горутина записывает переменную token (и еще переменную err!), а другая читает, поэтому вы должны синхронизировать доступ.

Поскольку token не является полем структуры threatq, ставить защищающий его мьютекс было бы неразумно. Всегда размещайте мьютекс рядом с данными, которые он должен защищать.

Некоторые примечания: как упоминалось ранее, вы также записываете и читаете локальную переменную err из нескольких горутин. Вы не должны этого делать, вместо этого создайте другую локальную переменную для хранения ошибки из других горутин (если только вы не хотите "переносить" ошибку между горутинами, но здесь это не так).

Смотрите связанные вопросы:

Неизменяемость строки и параллелизм

Должны ли мы синхронизировать назначение переменных в горутине?

Структура golang с одновременным чтением и записью без блокировки также работает нормально?

Чтение значений из другого потока

Почему этот код вызывает гонку данных?

большое спасибо. Вы правы, токен не является полем моей структуры, поэтому мне нужно использовать простой «автономный» мьютекс непосредственно внутри кода?

fallais 22.05.2019 12:05

@Elwyn Поместите мьютекс рядом с переменной token. Если у вас есть этот шаблон, используемый в нескольких местах вашего приложения, рассмотрите возможность создания типа структуры, обертывающего строковое поле и защищающего его мьютекса, и вы даже можете добавить методы для обеспечения безопасного одновременного чтения/записи. Хороший пример см. в разделе Когда вы встраиваете мьютекс в структуру в Go?.

icza 22.05.2019 12:06

вот где я теряюсь, как простая переменная мьютекса рядом с token, err := c.authenticate(c.clientID, c.email, c.password) защищает его? Я прекрасно вижу силу мьютекса, когда он вложен в структуру и защищает ее, но в этом случае... я теряюсь.

fallais 22.05.2019 12:08

@Elwyn Помещение рядом с token не защищает переменную token. Также не оборачивает их в структуру. С использованием мьютекс правильно защищает переменную. Вы должны поместить его рядом с token, чтобы вы знали, что цель этого мьютекса предназначен для защиты переменной token.

icza 22.05.2019 12:16

Другие вопросы по теме