Многопоточность: как заблокировать объект одним или несколькими потоками - PullRequest
1 голос
/ 16 августа 2010

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

Сразу после загрузки каждого объекта в массиве я могу отобразить массив в пользовательском интерфейсе. Параллельно с этим я запускаю вычисления по массиву. Объекту SlowDataComputation поручено сообщать результаты в пользовательский интерфейс (который, в свою очередь, визуализирует изменение конкретного объекта SlowData).

Вот как это будет выглядеть:

void main()
{
  std::vector<SlowData> aData;
  aData.reserve(1000000); // one million instances

  Fast_PopulateVector(aData);

  DataUi aUi;

  SlowDataComputation aCalc;
  aCalc.SetUiCallback(aUi);           // instruct the object to periodically
                                      // report computation results to the UI

  aCalc.Slow_ComputeInSeveralThreads(aData);

  aUi.VisualizeInMessageLoop(aData);  // message loop that exits upon user signal

  if ( aCalc.StillWorking() )
    aCalc.Stop();                     // terminate threads gradually

  // after VisualizeInMessageLoop returns, aData will then be destroyed
}

Я хочу, чтобы SlowDataComputation запустил несколько потоков, каждый из которых обрабатывал бы определенный сегмент в массиве:

class SlowDataComputation
{
  std::vector<SlowData> * myData;
  DataUi                * myUI;

public:
  void Slow_ComputeInSeveralThreads(std::vector<SlowData> & theV)
  {
    myData = &theV;

    size_t aSize = myData->size();
    size_t aNumThreads = 10;
    size_t aBlockSize = aSize / aNumThreads;

    for (size_ti = 0; i < aNumThreads; i++)
    {
      ComputationThread aThr(myData);
      aThr.SetBoundary(i * aBlockSize, (i+1) * aBlockSize);
      aThr.SetUiCallback(myUI);

      aThr.Run();   // process a given segment in the array
    }
  }
};

Наконец, вот несколько псевдокодов для пользовательского интерфейса:

class DataUi
{
  std::vector<SlowData> * myData;

public:
  void VisualizeInMessageLoop()
  {
    Message aMsg;

    while ( HasMessage(aMsg) )
      if (aMsg.Code == Message::MSG_PROGRAM_QUIT)
        SignalQuit();  // next time, HasMessage will return false

    // return from message loop
  }
};

Вопрос в : как обезопасить уничтожение SlowData экземпляров, чтобы, если какой-либо из десяти вычислительных потоков в настоящее время работает с объектом, уничтожение должно ждать пока не завершится каждый из этих вычислительных потоков (либо потому, что он завершил обработку, либо потому, что был вызван метод SlowDataComputation::Stop)? Какой примитив синхронизации наиболее подходит для этой задачи?

Мне удалось решить эту проблему с помощью одного вычислительного потока. Я использовал Критические Разделы. Но это решение плохо масштабируется для нескольких вычислительных потоков.

1 Ответ

1 голос
/ 16 августа 2010

В конце вашей main функции join все ваши темы с pthread_join Что-то вроде ...

  for(t=0; t<NUM_THREADS; t++) {
     rc = pthread_join(thread[t], &status);
     //check rc and status
  }
  //destroy shared data safely. All the threads are done.

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

...