Нужен ли в этом случае мьютекс? Я обновляю токен с помощью горутины, токен используется в другой горутине. Другими словами, будет ли мой токен в какой-то момент пустым, чтобы ответом был 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
}
...
Да, вы также можете попробовать запустить этот тест с включенным флагом -race
. Детектор гонки Go, вероятно, скажет вам, что токен является общей переменной для нескольких горутин. Таким образом, он должен быть защищен с помощью Mutex
или RWMutex
.
В вашем случае я думаю, что RWMutex
более подходит, потому что есть одна горутина, которая изменяет (то есть записывает) состояние token
каждые 30 минут, а другая горутина считывает его значение.
Если вы не защитите общую переменную блокировкой, вторая горутина может прочитать старое значение token
, срок действия которого может быть просрочен.
Правило простое: если к переменной обращаются из нескольких горутин и хотя бы одна из них является записью, необходима явная синхронизация.
В вашем случае так: одна ваша горутина записывает переменную token
(и еще переменную err
!), а другая читает, поэтому вы должны синхронизировать доступ.
Поскольку token
не является полем структуры threatq
, ставить защищающий его мьютекс было бы неразумно. Всегда размещайте мьютекс рядом с данными, которые он должен защищать.
Некоторые примечания: как упоминалось ранее, вы также записываете и читаете локальную переменную err
из нескольких горутин. Вы не должны этого делать, вместо этого создайте другую локальную переменную для хранения ошибки из других горутин (если только вы не хотите "переносить" ошибку между горутинами, но здесь это не так).
Смотрите связанные вопросы:
Неизменяемость строки и параллелизм
Должны ли мы синхронизировать назначение переменных в горутине?
Структура golang с одновременным чтением и записью без блокировки также работает нормально?
Чтение значений из другого потока
Почему этот код вызывает гонку данных?
большое спасибо. Вы правы, токен не является полем моей структуры, поэтому мне нужно использовать простой «автономный» мьютекс непосредственно внутри кода?
@Elwyn Поместите мьютекс рядом с переменной token
. Если у вас есть этот шаблон, используемый в нескольких местах вашего приложения, рассмотрите возможность создания типа структуры, обертывающего строковое поле и защищающего его мьютекса, и вы даже можете добавить методы для обеспечения безопасного одновременного чтения/записи. Хороший пример см. в разделе Когда вы встраиваете мьютекс в структуру в Go?.
вот где я теряюсь, как простая переменная мьютекса рядом с token, err := c.authenticate(c.clientID, c.email, c.password)
защищает его? Я прекрасно вижу силу мьютекса, когда он вложен в структуру и защищает ее, но в этом случае... я теряюсь.
@Elwyn Помещение рядом с token
не защищает переменную token
. Также не оборачивает их в структуру. С использованием мьютекс правильно защищает переменную. Вы должны поместить его рядом с token
, чтобы вы знали, что цель этого мьютекса предназначен для защиты переменной token
.
Конечно. Но если сомневаетесь: запустите его под детектором гонки.