Итак, во-первых, я поставил в тупик ваш merge_sort и объединить, запустив с двумя задачами и 4500000 элементов: без ошибки.
Для полной отладки вы можете предоставить полный код ...
здесь мой компилятор, слегка модифицированный код:
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
#include <ctime>
#include <cstdint>
#include <algorithm>
#include <thread>
/* define variables for the problem */
constexpr size_t const UPPER_LIM = 10;
constexpr size_t const LOWER_LIM = 1;
using namespace std;
/* function definitions */
void merge_sort(vector<int>& array, int left, int right){
return;
}
void merge(vector<int>& array, int left, int middle, int right){
return;
}
bool isTest_array_is_in_order(vector<int>& array, int LENGTH){
return false;
}
/**
* generate random numbers within the specified limit
*/
int generate_random_number(unsigned int lower_limit, unsigned int upper_limit){
return lower_limit + (upper_limit - lower_limit) * ((double)rand() / RAND_MAX);
}
/**
* assigns work to each thread to perform merge sort
*/
void thread_merge_sort(vector<int> &arr, int thread_id, int NUM_THREADS, int NUMBERS_PER_THREAD, int OFFSET){
int left = thread_id * (NUMBERS_PER_THREAD);
int right = (thread_id + 1) * (NUMBERS_PER_THREAD) - 1;
if (thread_id == NUM_THREADS - 1) {
right += OFFSET;
}
int middle = left + (right - left) / 2;
if (left < right) {
merge_sort(arr, left, right);
merge_sort(arr, left + 1, right);
merge(arr, left, middle, right);
}
}
int main(int argc, const char * argv[]){
int const NUM_THREADS = 2; //atoi (argv[1]);
int const LENGTH = 4500000; //atoi(argv[2]);
int const NUMBERS_PER_THREAD = LENGTH / NUM_THREADS;
int const OFFSET = LENGTH % NUM_THREADS;
cout << sizeof(int) << "\n";
srand(time(0)) ;
std::vector<int> array;
array.reserve(LENGTH);
/* initialize array with random numbers */
for(int ii=0; ii < LENGTH; ++ii){
array.push_back(generate_random_number(LOWER_LIM, UPPER_LIM));
}
/* begin timing */
auto start = std::chrono::high_resolution_clock::now();
const size_t nthreads = NUM_THREADS; //std::thread::hardware_concurrency();
{
// Pre loop
std::cout<<"parallel ("<<nthreads<<" threads):"<<std::endl;
std::vector<std::thread> workers;
for(std::size_t tt=0; tt<nthreads; ++tt){
workers.push_back(thread(thread_merge_sort, ref(array), tt, nthreads, NUMBERS_PER_THREAD, OFFSET));
}
// await thread termination
for(thread& t: workers) {
t.join();
}
}
auto elapsed = std::chrono::high_resolution_clock::now() - start;
auto usec = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
// and print time
std::cout << "Spent " << usec << " executing " << nthreads << " in parallel " << " array size " << array.size() << "\n";
/* end timing */
return 0;
}
[Edit]:
Ваш isTest_array_is_in_order не может работать, так как вы возвращаетесь сразу после сравнения первых двух элементов.
bool isTest_array_is_in_order(vector<int>& arr, int LENGTH)
{
for(int i=1;i<LENGTH;i++){
if(arr[i]>=arr[i-1]){
return true;
} else{
return false;
}
}
}
вот версия, которая должна работать:
/**
* test to ensure that the array is in sorted order
*/
bool isTest_array_is_in_order(vector<int>& arr, int LENGTH){
bool unorderd = false;
for(int ii=1;ii<LENGTH;++ii){
if(arr[ii]<arr[ii-1]){
unorderd = true;
break;
}
}
return !unorderd;
}
[Редактировать]:
Итак, сначала по вашему коду я смог подтвердить ваши ошибки segfaults
Я изменил код, и теперь он, кажется, работает довольно хорошо, только что проверил 16 потоков для 44999999 элементов, прекрасно работает
После просмотра вашего кода он вылетел прямо здесь:
/* merge function */
void merge(vector<int>& arr, int left, int middle, int right) {
int i = 0;
int j = 0;
int k = 0;
int left_length = middle - left + 1;
int right_length = right - middle;
int left_array[left_length];
int right_array[right_length];
Здесь вы создаете 2 локальных массива, но в стеке, а не в куче. Как правило, размер стека ограничен в зависимости от вашей ОС некоторым низким МБ, например, 10 или более.
Поэтому я заменил ваши C -массивы векторами и оптимизировал код немного дальше: более сложные типы, изменив основной, так что теперь я могу сортировать разные рандомизированные варианты за один прогон.
так вот мой код:
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <cstdint>
#include <thread>
#include <chrono>
#include <ctime>
#include <iterator>
#include <vector>
#include <array>
#include <random>
#include <algorithm>
using namespace std;
using idx_t = size_t;
using data_t = int;
/* define variables for the problem */
constexpr data_t const UPPER_LIM = 2000000;
constexpr data_t const LOWER_LIM = 0;
constexpr idx_t const REPEAT_CNT = 10000;
/* function definitions */
std::string to_array_str(vector<data_t>& arr, idx_t max_elem){
std::stringstream ss;
idx_t ii=1;
idx_t cnt = 0;
for(auto _d:arr){
ss << setw(8) << _d;
if(0==(ii%10)){
ss << ",\n";
ii=0;
}else{
ss << ", ";
}
if(cnt>=max_elem) break;
++ii;
++cnt;
}
return ss.str();
}
/**
* generate random numbers within the specified limit
*/
data_t generate_random_number(data_t const lower_limit, data_t const upper_limit){
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<data_t> dis(lower_limit, upper_limit);
return dis(gen);
//return lower_limit + (upper_limit - lower_limit) * ((double)rand() / RAND_MAX);
}
/**
* test to ensure that the array is in sorted order
*/
bool isTest_array_is_in_order(vector<data_t>& arr){
bool unorderd = false;
for(idx_t ii=1;ii<arr.size();++ii){
if(arr[ii]<arr[ii-1]){
unorderd = true;
cout << "unordered Index: " << ii << "\n";
cout << "arr[ii] " << arr[ii] << " arr[ii-1] " << arr[ii-1] << "\n";
break;
}
}
return !unorderd;
}
/**
* merge function
*/
void merge(vector<data_t>& arr, idx_t const left, idx_t const middle, idx_t const right) {
idx_t const left_length = middle - left + 1;
idx_t const right_length = right - middle;
vector<data_t> left_array( left_length);
vector<data_t> right_array(right_length);
constexpr bool const use_loopcopy = true;
if(use_loopcopy){
/* copy values to left array */
for(idx_t ii=0; ii < left_length; ++ii){
left_array[ii] = arr[left + ii];
}
/* copy values to right array */
for(idx_t ii=0; ii < right_length; ++ii){
right_array[ii] = arr[middle + 1 + ii];
}
}
constexpr bool const use_libcode = false;
if(use_libcode){
{
auto from = arr.begin();
auto to = from;
std::advance(from,left);
std::advance(to,middle+1);
std::copy(from,to,left_array.begin());
}
{
auto from = arr.begin();
auto to = from;
std::advance(from,middle+1);
std::advance(to,right+1);
std::copy(from,to,right_array.begin());
}
}
idx_t ii = 0;
idx_t jj = 0;
idx_t kk = 0;
/** chose from right and left arrays and copy */
while((ii < left_length) && (jj < right_length)){
if(left_array[ii] <= right_array[jj]){
arr[left + kk] = left_array[ii];
++ii;
} else {
arr[left + kk] = right_array[jj];
++jj;
}
++kk;
}
/* copy the remaining values to the array */
while(ii < left_length){
arr[left + kk] = left_array[ii];
++kk;
++ii;
}
while(jj < right_length){
arr[left + kk] = right_array[jj];
++kk;
++jj;
}
return;
}
/**
* perform merge sort
*/
void merge_sort(vector<data_t>& arr, idx_t const left, idx_t const right) {
if(left < right){
idx_t middle = left + ((right - left)>>1);
//Divide
merge_sort(arr, left, middle);
merge_sort(arr, middle + 1, right);
//Conquer
merge(arr, left, middle, right);
}
return;
}
/**
* assigns work to each thread to perform merge sort
*/
void thread_merge_sort(vector<data_t>& arr, idx_t const thread_id, idx_t const NUM_THREADS, idx_t const NUMBERS_PER_THREAD, idx_t const OFFSET){
idx_t left = thread_id * (NUMBERS_PER_THREAD);
idx_t right = (thread_id + 1) * (NUMBERS_PER_THREAD) - 1;
if(thread_id == (NUM_THREADS - 1)) {
right += OFFSET;
}
merge_sort(arr,left,right);
return;
}
int main(int argc, const char * argv[]){
/*
int const NUM_THREADS = 16; //atoi (argv[1]);
int const LENGTH = 1000000000; //atoi(argv[2]);
*/
/*
int const NUM_THREADS = 8; //atoi (argv[1]);
int const LENGTH = 449999; //atoi(argv[2]);
*/
int const NUM_THREADS = 8; //atoi (argv[1]);
int const LENGTH = 100; //atoi(argv[2])
int const NUMBERS_PER_THREAD = LENGTH / NUM_THREADS;
int const OFFSET = LENGTH % NUM_THREADS;
cout << sizeof(int) << "\n";
//srand(time(0)) ;
std::vector<int> array(LENGTH);
//array.reserve(LENGTH);
constexpr size_t nthreads = NUM_THREADS; //std::thread::hardware_concurrency();
std::cout<<"parallel ("<<nthreads<<" threads):"<<std::endl;
uint64_t time = 0;
bool ordered = true;
for(idx_t ii=0; ii<REPEAT_CNT; ++ii){
/* initialize array with random numbers */
for(int ii=0; ii < LENGTH; ++ii){
//array.push_back(generate_random_number(LOWER_LIM, UPPER_LIM));
array[ii]=(generate_random_number(LOWER_LIM, UPPER_LIM));
}
/* begin timing */
auto start = std::chrono::high_resolution_clock::now();
{
// Pre loop
std::vector<std::thread> workers;
for(std::size_t tt=0; tt<nthreads; ++tt){
workers.push_back(thread(thread_merge_sort, ref(array), tt, nthreads, NUMBERS_PER_THREAD, OFFSET));
}
// await thread termination
for(thread& t: workers) {
t.join();
}
ordered &= isTest_array_is_in_order(array);
if(!ordered) break;
}
auto elapsed = std::chrono::high_resolution_clock::now() - start;
auto usec = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
time = (usec + time)>>1;
}
// and print time
//cout << "Spent " << usec << "[µs] executing " << nthreads << " Threads in parallel working on " << array.size() << " elements " << "\n";
cout << "Spent " << time << "[µs] executing " << nthreads << " Threads in parallel working on " << array.size() << " elements " << "\n";
//cout << "Result is ordered: " << isTest_array_is_in_order(array) << "\n";
cout << "Result is ordered: " << ordered << "\n";
cout << to_array_str(array,100) << "\n";
return 0;
}
Но даже если этот код больше не вызывает segfaults, поиграйте с По разным параметрам, оказывается, что он когда-либо производит отсортированный массив, за исключением однопотоковых запусков. Таким образом, анализ chqrl ie является правильным, поскольку отсортированные части отдельных потоков также должны быть отсортированы.