Всем привет.
UPD2: добавлены реализации boost и OpenMP, почищен код, добавлены комменты в код, немного переформулировано ТЗ (суть не поменялась).
Признаюсь: первый опыт с многопоточной программой, так что прошу ногами сильно не бить.
  Решил написать простую программу генерации простых чисел по методу вычеркивания. В развитии этой темы, написал 6 алгоритмов, 4 из которых многопоточные, близнецы, но используют std:thread (метод Initiate3), std:async (Initiate4), boost (Initiate5), OpenMP (Initiate6). Изначально ожидал, что многопоточные алгоритмы загрузят все ядра процессора на 100% и дадут увеличение скорости работы программы. Результаты удивили:
 - Все реализации выполняются примерно за одно время (даже OpenMP).
 - Многопоточные реализации не быстрее однопоточной, а иногда даже медленнее!!!
   std:thread - грузит одно ядро на 100%
   std:async - грузит два ядра, общая нагрузка не более 100% одного ядра.
   boost - грузит одно ядро
   OpenMP - грузит два ядра (суммарная нагрузка 200%), но при этом выполняется не быстрее (обогреватель воздуха помещения)!
  Вопрос 1: почему Initiate3,4,5 не грузит все ядра на полную мощность?
  Вопрос 2: почему Initiate6 (OpneMP) грузит все ядра, но пи этом не быстрее?
  Вопрос 3: Как получить профит от многопоточности в данной конкретной задаче?
Для тех, кто решится помочь - заранее спасибо, и вот инфа в помощь:
Краткое представление алгоритма. Создается массив, элементы которого соответствует числам 3, 5, 7... (ведь четные числа не простые априори). Если соотв. число простое, то значение элемента массива 1, если не простое - 0 (для чистоты эксперимента специально заменил bool на unsigned char). Заполняет массив функция Initiate, в параметрах которой - максимальное число до которого искать. Initiate1 втупую проверяет каждое число, Initiate2 - при нахождении простого числа проходит массив вперед и убирает (помечает не-простыми) соотв. числа, Initiate3,4,5,6 - то же, но с многопоточностью. MarkNonPrime2 и MarkNonPrime3 - близнецы, но вторая предназначена для запуска в отдельном потоке. Остальное, думаю, будет понятно из кода.
Запускать так:
$ g++ -std=c++11 -lpthread -L/usr/lib -lboost_thread prime.cpp -fopenmp -O0 -o prime && time ./prime
Выбор реализации - в main() вызвать нужный метод InitiateX.
Длительность выполнения программы регулировать изменяя параметр InitiateX в main.
Собственно код (prime.cpp):
#include <iostream>
#include <iomanip>
#include <vector>
#include <thread>
#include <future>
#include <boost/thread/thread.hpp>
using namespace std;
// Maximum threads that could be spawned (except OpenMP)
#define MAX_THREAD 100
class CPrimeNumbers{
public:
  vector<unsigned char> numbers; // Array starts with 3 and has a step of 2: 3, 5, 7, 9 ...
  
  inline uint NumberToIndex(const uint number) {return (number-3)/2;}; // BUG: check whether number is < 3
  inline uint IndexToNumber(const uint index) {return index*2+3;};
  
  void MarkNonPrime2(const uint v,const uint max); // Single thread version: mark all N*v numbers (N - integer, N*v<=max) as non-prime
  static void MarkNonPrime3(CPrimeNumbers *sno, const uint v,const uint max); // Multithreading version: mark all N*v numbers (N - integer, N*v<=max) as non-prime
public:
  // Find all prime numbers - different realizations
  void Initiate1(const uint max=6); // Simple algorithm - checking each number
  void Initiate2(const uint max=6); // Marking-forward algorithm, single thread
  void Initiate3(const uint max=6); // Marking-forward algorithm, multithreading using C++11, std::thread
  void Initiate4(const uint max=6); // Marking-forward algorithm, multithreading using C++11, std::async
  void Initiate5(const uint max=6); // Marking-forward algorithm, multithreading using Boost
  void Initiate6(const uint max=6); // Marking-forward algorithm, multithreading using OpenMP
  
  void Print(); // Outhput prime numbers found
  bool IsPrime(uint number); // Check whether given number is prime
};
bool CPrimeNumbers::IsPrime(uint number)
{
  uint i;
  
  // BUG: check whether number is =0
  if (number<4)
    return true;
  
  if (number%2==0)
    return false;
  
  for (i=0;i<NumberToIndex(number);i++)
    if ( numbers[i]==1 && number%IndexToNumber(i) == 0 )
      return false;
    
  return true;
};
/*static*/ void CPrimeNumbers::MarkNonPrime3(CPrimeNumbers *sno, const uint v,const uint max)
{
  uint n;
  
  n=v*3;
  while (n<=max) {
    sno->numbers[sno->NumberToIndex(n)]=0;
    n+=v*2;
  }
};
void CPrimeNumbers::MarkNonPrime2(const uint v,const uint max)
{
  uint n;
  
  n=v*3;
  while (n<=max) {
    numbers[NumberToIndex(n)]=0;
    n+=v*2;
  }
};
void CPrimeNumbers::Initiate6(const uint max)
{
  uint head,i;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if ( numbers[NumberToIndex(head)]==1 ) { // Is prime/unchecked yet
      if (!IsPrime(head)) { // Is not prime
        numbers[NumberToIndex(head)]=0;
      }
      else{ // Is prime
        /*********** Multithreading using OpenMP ***********/
        #pragma omp parallel
        {
          MarkNonPrime3(this,head,max);
        }
      }
    }
  };
};
void CPrimeNumbers::Initiate5(const uint max)
{
  uint head,i;
  vector<boost::thread> threads;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if ( numbers[NumberToIndex(head)]==1 ) { // Is prime/unchecked yet
      if (!IsPrime(head)) { // Is not prime
        numbers[NumberToIndex(head)]=0;
      }
      else{ // Is prime
        /*********** Multithreading using Boost ***********/
        if ( threads.size()==MAX_THREAD) {
          threads[0].join();
          threads.erase(threads.begin());
        }
        threads.push_back( boost::thread(MarkNonPrime3,this,head,max) );
      }
    }
  };
  
  for (auto t=threads.begin();t!=threads.end();t++)
    t->join();
};
void CPrimeNumbers::Initiate4(const uint max)
{
  uint head,i;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if ( numbers[NumberToIndex(head)]==1 ) { // Is prime/unchecked yet
      if (!IsPrime(head)) { // Is not prime
        numbers[NumberToIndex(head)]=0;
      }
      else{ // Is prime
        /*********** multithreading using C++11, std::async ***********/
        async(launch::async,  MarkNonPrime3,this,head,max );
      }
    }
  };
};
void CPrimeNumbers::Initiate3(const uint max)
{
  uint head,i;
  vector<thread> threads;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if ( numbers[NumberToIndex(head)]==1 ) { // Is prime/unchecked yet
      if (!IsPrime(head)) { // Is not prime
        numbers[NumberToIndex(head)]=0;
      }
      else{ // Is prime
        /*********** Multithreading using C++11, std::thread ***********/
        if ( threads.size()==MAX_THREAD) {
          threads[0].join();
          threads.erase(threads.begin());
        }
        threads.push_back( thread(MarkNonPrime3,this,head,max) );
      }
    }
  };
  
  for (auto t=threads.begin();t!=threads.end();t++)
    t->join();
};
void CPrimeNumbers::Initiate2(const uint max)
{
  uint head,i;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if ( numbers[NumberToIndex(head)]==1 ) { // Is prime/unchecked yet
      if (!IsPrime(head)) { // Is not prime
        numbers[NumberToIndex(head)]=0;
      }
      else{ // Is prime
        /*********** Single thread ***********/
        MarkNonPrime2 (head,max);
      }
    }
  };
  
};
void CPrimeNumbers::Initiate1(const uint max)
{
  uint i;
  uint head;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if (! IsPrime(head) )
      numbers[NumberToIndex(head)]=0;
  };
  
};
void CPrimeNumbers::Print()
{
  uint n;
  
  n=3;
  for (auto i:numbers) {
    if (i) cout << n << " ";
    n+=2;
  }
  cout << endl;
}
int main()
{
  CPrimeNumbers s;
  
  /*********** Choose the algorithm ***********/
  s.Initiate1(100000);
  s.Print();
  
  return 0;
}





