Как многопоточность это? - PullRequest
0 голосов
/ 25 мая 2010

Я хочу иметь две темы.Первый поток 1 иногда вызывает следующую псевдофункцию:

void waitForThread2() {
  if (thread2 is not idle) {
    return;
  }
  notifyThread2IamReady(); // i.e. via 1st condition variable
  Wait for thread2 to finish exclusive access. // i.e. via 2nd condition variable.
}

Второй поток 2 всегда находится в следующем псевдоцикле:

for (;;) {
  Notify thread1 I am idle.
  Wait for thread1 to be ready. // i.e. via 1st condition variable.
  Notify thread1 I am exclusive.
  Do some work while thread1 is blocked.
  Notify thread1 I am busy. // i.e. via 2nd condition variable.
  Do some work in parallel with thread1.
}

Каков наилучший способ написать это так, чтобы обаthread1 и thread2 максимально загружены на машине с несколькими ядрами.Я хотел бы избежать длительных задержек между уведомлением в одном потоке и обнаружением другим.Я попытался использовать условные переменные pthread, но обнаружил, что задержка между thread2, выполняющим «уведомить thread1, что я занят», и циклом в waitForThread2 () для thear2IsExclusive () может составлять почти одну секунду.Затем я попытался использовать переменную разделяемой переменной sig_atomic_t для управления тем же, но что-то идет не так, поэтому я не должен делать это правильно.

Ответы [ 3 ]

3 голосов
/ 25 мая 2010

Похоже, что вы должны использовать семафоры для передачи сигналов, вместо того, чтобы иметь циклы while, которые простаивают потоки, ожидая возникновения какого-либо условия. Плохие петли плохие.

1 голос
/ 25 мая 2010

Я смотрю на меня так, будто ты пытаешься встретиться (термин от Ады).

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

Первый поток «вызывает» второй поток - с немедленным тайм-аутом, если второй поток недоступен для приема вызова.

Ада поддерживает это непосредственно на языке, но при условии, что перенос на Аду не вариант ...

Это можно реализовать с помощью трех семафоров. Семафор 1 указывает, что поток 1 готов к свиданию. Семафор 2 указывает, что поток 2 готов к рандеву. Семафор 3 указывает, что встреча завершена.

Тема 1: по умолчанию используется семафор 1.

 if Semaphore 2.acquire(timeout = 0) is successful # Thread 2 is ready
     Semaphore 1.release() # Indicate I am ready
     Semaphore 3.acquire() # Wait until the rendevous is complete.
     Semaphore 3.release()
     Semaphore 1.acquire() # Indicate I am not ready
     Semaphore 2.release() # I am no longer using thread 2.

 Do concurrent work 

Поток 2: приобретены значения по умолчанию с семафором 2.

 Loop forever
     Semaphore 3.acquire() # Indicate Rendevous is not complete.
     Semaphore_2.release() # Indicate I am ready
     Semaphore_1.acquire() # Wait for Thread 1 to be ready
     Joint processing
     Semaphore 1.release() # I am no longer using thread 1.
     Semaphore 3.release() # Rendevous is complete.
     Semaphore 2.acquire() # I am not ready

 Post-processing

ПРИМЕЧАНИЕ. Написано с нуля, не проверено. Выглядит намного сложнее, чем я думал, когда я начинал; я что-то пропустил?

1 голос
/ 25 мая 2010

Вместо того, чтобы ваши потоки сообщали друг другу "Я занят" или "Я не занят", попробуйте думать с точки зрения объектов данных, над которыми работают ваши потоки.

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

Когда поток вносит изменения в общее состояние данных, которое могут ожидать другие потоки, сигнализируют переменную условия, чтобы уведомить их. (Например, если поток источника добавляет данные в очередь, он может сигнализировать о состоянии «dataAvailable», которого может ожидать потребитель.)

...