pthread实现快速排序

 

1. 实验内容与方法

  1. 初始化数组。数组中的值使用c++11中的random类随机生成0到2000之间的double值,将数组中的值存入到文件中,供后续调用使用以保证并行和串行进行快速排序时的数组是相同的。
  2. 程序计时。使用c++11中的std::chrono库,使用system_clock表示当前的系统时钟,系统中运行的所有进程使用now()得到的时间是一致的。
  3. 串行执行快速排序。不使用c++中的sort函数,手动实现快速排序。
  4. 并行执行快速排序。将数组分成n段,使用n个线程并行对每段进行快速排序处理。需要使用pthread_barrier函数保证所有线程都将分段排好序之后,进行类似归并排序。因为可能存在数组分段后长度不同的问题,自定义了一个类用来保存分段的左右端点位置。
  5. 数组大小和数组中的值不变,修改线程数。分别设置线程数为2、3、4、8个,统计运行时间。
  6. 线程数不变,修改数组大小。将数组大小分别修改为5000万和1亿,分别运行pthread统计运行时间。
  7.  

2. 实验过程

实验设备CPU(i7-7700  3.6GHz, 4核),内存16G,操作系统Ubuntu 18.04,IDE CLion。

2.1 运行时间

经过代码运行计时,得到以下的实验结果表格。

运行时间/秒

2000万

5000万

1亿

1核

6.72747

25.1391

76.2641

2核

3.36834

10.3938

27.2989

3核

2.39181

7.15399

17.0872

4核

2.01613

5.69332

13.0158

8核

2.09013

5.49922

11.2955

 

2.2 加速比

加速比

2000万

5000万

1亿

1核

1

1

1

2核

1.99726572

2.41866305

2.79366934

3核

2.81271088

3.51399708

4.46322979

4核

3.33682352

4.41554313

5.85934787

8核

3.21868496

4.57139376

6.75172414

 

2.3 图表

绘制成图表,如下图所示。

3  实验分析

从实验结果和加速比可以看出:

1 随着数据量的增大,快排所需的时间也相应增加;

2 在4核并行内,快排运行的加速比与运行的核心近似成正比;虽然系统显示为8核,但只有4个真正的核。所以当并行线程数大于4后,快排提升的效果并不明显,因为要进行线程的切换。

4 源代码

initVector.cpp

#include "iostream"
#include "fstream"
#include "random"
#include "vector"
#include "string"
#include "sstream"
#include "cstdlib"
using namespace std;
const int size = 20000000;

string path = "/home/dadan/Downloads/vector.txt";

void writeAndInitVector(int size) {
    vector<double> res(size, 0.0);
    default_random_engine engine;
    uniform_real_distribution<double> u(0.0, 20000);
    for (int i = 0; i < size; ++i) {
        res[i] = u(engine);
    }
    ofstream outfile(path);
    for (int i = 0; i < size; ++i) {
        outfile << res[i] << endl;
    }
    outfile.close();
}

void loadVector(int size) {
    vector<double> res(size, 0);
    ifstream file(path);
    string line;
    for (int i = 0; i < size; ++i) {
        getline(file, line);
        res[i] = stod(line);
    }
    file.close();
}

int main() {
    writeAndInitVector(size);
    //loadVector(size);
    return 0;
}

quickSort.cpp

#include <iostream>
#include "pthread.h"
#include "vector"
#include "fstream"
#include "cstring"
#include "climits"
#include "chrono"
#include "ctime"

using namespace std;
using namespace std::chrono;

const long SIZE = 20000000; //the size of vector that need to be sorted
const int THREADS_NUM = 3; // the number of threads
long sortNumPerThread = SIZE / THREADS_NUM; // the number of vector that every thread needs to sort
string path = "/home/dadan/Downloads/vector.txt"; // file path of vector

vector<double> vec(SIZE), sortedVec(SIZE);
pthread_barrier_t barrier;

class Section{
public:
    int left;
    int right;
    Section(){

    };
};

void loadVector();

void quickSort(int left, int right);

void *pthread_sort(void *arg);

void merge();

void serial_quick_sort();

int main() {
    //serial_quick_sort();
    loadVector();

    pthread_t tid;
    pthread_barrier_init(&barrier, NULL, THREADS_NUM + 1);
    auto start = system_clock::now();
    for (int i = 0; i < THREADS_NUM; ++i) {
        Section* section = new Section;
        section->left = i * sortNumPerThread;
        if (i == THREADS_NUM - 1) {
            section->right = SIZE - 1;
        } else {
            section->right = (i + 1) * sortNumPerThread - 1;
        }
        int status = pthread_create(&tid, NULL, pthread_sort, (void *) (section));
        if (status != 0) {
            cout << "create thread error" << endl;
            return -1;
        }
    }

    //main thread wait
    pthread_barrier_wait(&barrier);

    //merge results of per thread
    merge();
    auto end = system_clock::now();
    auto duration = duration_cast<microseconds>(end - start);
    cout << THREADS_NUM << " threads pthread-parallel quick sort takes "
         << double(duration.count()) * microseconds::period::num / microseconds::period::den << " seconds" << endl;
    return 0;
}

void loadVector() {
    ifstream read_file(path);
    string line;
    for (int i = 0; i < SIZE; ++i) {
        getline(read_file, line);
        vec[i] = stod(line);
    }
    read_file.close();
}

void quickSort(int start, int end) {
    if (start >= end)
        return;
    double base = vec[end];
    int left = start, right = end - 1;
    while (true) {
        while (vec[left] < base)
            ++left;
        while (vec[right] >= base)
            --right;
        if (left >= right)
            break;
        swap(vec[left], vec[right]);
    }
    if (vec[left] >= vec[end])
        swap(vec[left], vec[end]);
    else
        ++left;
    quickSort(start, left - 1);
    quickSort(left + 1, end);
}

void merge() {
    vector<int> index(THREADS_NUM), index_most(THREADS_NUM);
    for (int i = 0; i < THREADS_NUM; ++i) {
        index[i] = i * sortNumPerThread;
        if (i == THREADS_NUM - 1) {
            index_most[i] = SIZE;
        } else {
            index_most[i] = (i + 1) * sortNumPerThread;
        }
    }
    for (int i = 0; i < SIZE; ++i) {
        int min_index;
        double min_num = INT_MAX;
        for (int j = 0; j < THREADS_NUM; ++j) {
            if ((index[j] < (j + 1) * sortNumPerThread) && (vec[index[j]] < min_num)) {
                min_num = vec[index[j]];
                min_index = j;
            }
        }
        sortedVec[i] = vec[index[min_index]];
        index[min_index]++;
    }
}

void serial_quick_sort() {
    loadVector();
    auto start = system_clock::now();
    quickSort(0, SIZE - 1);
    auto end = system_clock::now();
    auto duration = duration_cast<microseconds>(end - start);
    cout << "serial quick sort takes "
         << double(duration.count()) * microseconds::period::num / microseconds::period::den << " seconds" << endl;
}

void *pthread_sort(void *arg) {
    Section* section = (Section*)arg;
    quickSort(section->left, section->right);

    //wait other threads
    pthread_barrier_wait(&barrier);
}

 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
下面是一个使用pthread并行线程池实现快速排序的C程序示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #define MAX_THREADS 4 // 最大线程数 #define MAX_SIZE 100000 // 待排序数组的最大大小 int num_threads = 1; // 当前线程数 int data[MAX_SIZE]; // 待排序数组 int data_size = 0; // 待排序数组的大小 pthread_mutex_t lock; // 互斥锁 // 交换两个元素的值 void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } // 分割数组,返回中间值的下标 int partition(int left, int right) { int pivot = data[right]; int i = left - 1; for (int j = left; j < right; j++) { if (data[j] <= pivot) { i++; swap(&data[i], &data[j]); } } swap(&data[i + 1], &data[right]); return i + 1; } // 快速排序 void quick_sort(int left, int right) { if (left < right) { int mid = partition(left, right); quick_sort(left, mid - 1); quick_sort(mid + 1, right); } } // 线程池的工作线程 void *worker_thread(void *arg) { int *data_range = (int *)arg; int left = data_range[0]; int right = data_range[1]; quick_sort(left, right); pthread_mutex_lock(&lock); // 上锁 num_threads--; // 线程数减一 pthread_mutex_unlock(&lock); // 解锁 free(data_range); // 释放内存 pthread_exit(NULL); } // 创建线程池并启动工作线程 void thread_pool(int left, int right) { pthread_t threads[MAX_THREADS]; int i, j, step = (right - left + 1) / num_threads; for (i = 0, j = left; i < num_threads - 1; i++, j += step) { int *data_range = (int *)malloc(sizeof(int) * 2); data_range[0] = j; data_range[1] = j + step - 1; pthread_create(&threads[i], NULL, worker_thread, (void *)data_range); } int *data_range = (int *)malloc(sizeof(int) * 2); data_range[0] = j; data_range[1] = right; worker_thread((void *)data_range); // 最后一个线程由主线程执行 for (i = 0; i < num_threads - 1; i++) { pthread_join(threads[i], NULL); } } int main() { pthread_mutex_init(&lock, NULL); printf("请输入待排序数组的大小(不超过%d):", MAX_SIZE); scanf("%d", &data_size); printf("请输入待排序数组:"); for (int i = 0; i < data_size; i++) { scanf("%d", &data[i]); } printf("请输入线程数(不超过%d):", MAX_THREADS); scanf("%d", &num_threads); if (num_threads > MAX_THREADS) { num_threads = MAX_THREADS; } thread_pool(0, data_size - 1); quick_sort(0, data_size - 1); printf("排序结果:"); for (int i = 0; i < data_size; i++) { printf("%d ", data[i]); } printf("\n"); pthread_mutex_destroy(&lock); return 0; } ``` 该程序使用了一个线程池来实现并行化的快速排序算法。首先输入待排序数组的大小和数组元素,然后输入要使用的线程数。程序将待排序数组分割为若干个区间,每个区间交由一个工作线程来进行快速排序。最后,主线程对整个数组进行一次快速排序,以确保数组的完全有序。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值