多线程排序-复盘

调试工具

valgrind内存泄漏检测

参考连接:

GDB

time exe

代码实现

项目目标

  • 实现多线程排序

代码

/**
 * @file sort.c
 * @author binary (binary@techbootcamp)
 * @brief 多线程排序项目
 * @version 0.1
 * @date 2021-11-03
 * 
 * @copyright Copyright (c) 2021
 * 
 */
///////////////////////////////////////////////////////////////////////////////
//头文件区域,所需要的头文件,添加到这里。

#include <stdio.h>

#include <stdlib.h> // exit()
#include <pthread.h>
#include <unistd.h>
#include <string.h>

/*
gcc -o sort sort.c -w -lpthread
./sort
*/
///////////////////////////////////////////////////////////////////////////////
//宏定义

#define SIZE 500

#define thread_MAX 2

///////////////////////////////////////////////////////////////////////////////
//结构体

typedef struct
{
    int size;
    int data[SIZE];
} datas;
datas numbers;

typedef struct
{
    int start;
    int end;
} parameters;


///////////////////////////////////////////////////////////////////////////////
//变量声明

///////////////////////////////////////////////////////////////////////////////
//函数声明

/**
 * @brief 打印数据
 * 
 * @param array 
 */
void print_data(datas array);   // OK 

/**
 * @brief 检测数据是否已经排序
 * 
 * @param array 
 * @return true 
 * @return false 
 */
int is_sorted(datas array);     // OK

/**
 * @brief 排序线程的回调函数
 * 
 * @param params 
 * @return void* 
 */
void *sorter(void *params);

/**
 * @brief 合并线程的回调函数
 * 
 * @param params 
 * @return void* 
 */
void *merger(void *params);

/**
 * @brief 从文件中读取数据。(原始数据,未排序的)
 * 
 */
void input_data();            // OK

/**
 * @brief 排序线程的初始化和工作过程
 * 
 */
void handle_sorting();        // OK

/**
 * @brief 合并线程的初始化和工作过程
 * 
 */
void handle_merge();

/**
 * @brief 显示排序数据是否正确
 * 
 * 排序不正确,显示排序不正确,并打印出排序数据。
 * 排序正确,则显示排序正确。
 * 
 */
void show_data();           // OK

/**
 * @brief 输出数据到文件。(已经排好序的)
 * 
 */
void output_data();

/**
 * @brief 清理一些资源。比如动态内存分配的资源
 * 
 */
void cleanup();

//TODO:你的排序算法函数在这里声明

///////////////////////////////////////////////////////////////////////////////
//函数实现

/**
 * @brief 主函数人口
 * 
 * @param argc 参数个数
 * @param argv 参数数组
 * @return int 返回状态
 */
int main(int argc, char *argv[])
{
    input_data();
    handle_sorting();
    handle_merge();
    show_data();
    output_data();
    cleanup();
    return 0;
}

// @brief 打印数据
void print_data(datas array)
{
    printf("打印数据:");
    for (int k = 0; k <= array.size - 1; k++)
    {
        printf("%d,", array.data[k]);
    }
    putchar('\n');
}

// @brief 检测数据是否已经排序
int is_sorted(datas array)
{
    char flag = 0;
    if (array.size < 1)
    {
        printf("Input array is empty.\n");
        return 1;
    }

    for (int i = 1; i < array.size; i++)
    {
        if (array.data[i - 1] > array.data[i])
        {
                flag = 1;
        }
        if (flag)
        {
            return 1;
        }
    }
    return 0;
}

// @brief 排序线程的回调函数
void swap(int *a,int *b) //交換兩個變數
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

/*  排序 */
void sort_select(int * data, int size)
{
    int i, j, min;
    
    if (data == NULL || size <= 0)
    {
        printf("data error,sort_select().\n");
    }
    
    for (i = 0; i < size; i++)      // 从第一个,到最后第二个,每个都要和后面所有比较
    {
        min = i;                    // 默认选第一个是最小值
        for (j = i + 1; j <= size; j++)     // 后面一次比较的循环
        {
            if (data[i] > data[j])
            {
                swap(&data[i], &data[j]);
            }
        }
    }
}

// @params:存放起止位置的指针,p=params
void *sorter(void *params)
{
    // 选择排序
    parameters * p = (parameters *)params;
    // data指向保存源数组的开始位置
    int *data = &numbers.data[p->start];
    int size = p->end - p->start;   // 线程处理数据的大小

    //printf("size:%d.\n", size);
    sort_select(data, size);
}

void *merger(void *params)
{
    //printf("asdasdasd\n");
    parameters * p = (parameters *)params;
    int *data = &numbers.data[p->start];
    int size = p->end - p->start;   // 线程处理数据的大小
    sort_select(data, size);
}

void input_data()
{
    FILE *fp;
    char ch;
    char str[30] = {0}; 
    int i = 0, j = 0;
    
    numbers.size = 0;

    fp = fopen("sort", "r");        // 打开数文件夹
    if (fp == NULL)                     // 如果为空文件夹
    {
        printf("Empty txt file.\n");
        exit(1);
    }

    while ((ch = fgetc(fp)) != EOF)                   // 循环处理文件内容
    {
        if (ch != ',')      // 逗号分隔输入数据,不是逗号就是有效数据
        {
            str[i] = ch;    // 存储两个逗号之间的所有数字字符
            i++;
        }
        else                // 这时出现逗号,表示一个有效数字输入完毕
        {
            i = 0;          // 清零
            numbers.data[j++] = atoi(str);  // 将一个有效数字字符转成数字,并存入数组
            numbers.size++;                 // 存储数组数量加一
            memset(str, 0, sizeof(str));    // 清空暂存数组
        }
    }
    if (i != 0)             // 最后一个数组后面可能没有逗号
    {
        numbers.data[j] = atoi(str);            
        numbers.size++;
    }

    // print_data(numbers);     // 测试打印函数,测试输入数据是否正确
    // printf("is_sorted() : %d.\n", is_sorted(numbers));     // 测试是否正确排序函数
    fclose(fp);
}

// @brief 排序线程的初始化和工作过程
void handle_sorting()
{
    pthread_t ntid1, ntid2;
    parameters * param[2];
    int err1, err2;
    int len = numbers.size / thread_MAX;    // 两个线程的情况下,第二个开始位置
    //parameters * para[2];
    param[0] = (parameters *)malloc(sizeof(parameters));
    param[0]->start = 0;
    param[0]->end = len;
    param[1] = (parameters *)malloc(sizeof(parameters));
    param[1]->start = len + 1;
    param[1]->end = numbers.size - 1;
    // printf("param[0]->start=%d\nparam[0]->end=%d\nparam[1]->start=%d\nparam[1]->end=%d\n",
    //         param[0]->start, param[0]->end, param[1]->start, param[1]->end);
    
    /*  如何用for循环,创建任意多个线程处理,
        主要是地址分配,不清楚怎么任意分配 */
    // for (int i = 0; i < thread_MAX ; i++)
    // {
    //     err = pthread_create(&ntid, NULL, sorter, (void *)i);   // 创建新线程
    //     if(err != 0){ 
    //         fprintf(stderr, "error create:%s\n", strerror(err)); 
    //         exit(1); 
    //     } 
    // }

    err1 = pthread_create(&ntid1, NULL, sorter, (void *)param[0]);   // 创建新线程
    if(err1 != 0){ 
        fprintf(stderr, "error create:%s\n", strerror(err1)); 
        exit(1); 
    } 

    err2 = pthread_create(&ntid2, NULL, sorter, (void *)param[1]);   // 创建新线程
    if(err2 != 0){ 
        fprintf(stderr, "error create:%s\n", strerror(err2)); 
        exit(1); 
    } 
    pthread_join(ntid1, NULL);
    pthread_join(ntid2, NULL);

    free(param[0]);
    free(param[1]);
}

void handle_merge()
{
    pthread_t ntid;
    int err;

    parameters * para = (parameters *)malloc(sizeof(parameters));
    para->start = 0;
    para->end = numbers.size - 1;
    
    err = pthread_create(&ntid, NULL, merger, (void *)para);   // 创建新线程
    if(err != 0){ 
        fprintf(stderr, "error create:%s\n", strerror(err)); 
        exit(1); 
    } 
    pthread_join(ntid, NULL);
    //sleep(1);       // 不加延时会排序出错???
    free(para);     // 还不能放上面???
}

// @brief 显示排序数据是否正确
void show_data()
{
    int res = is_sorted(numbers);
     
    if (res)
    {
        printf("不正确排序.\n");
        print_data(numbers);
    } 
    else {
        printf("正确排序.\n");
        print_data(numbers);
    }
}

void output_data()
{
    FILE *fp;
    int i = 0;
    char ch;

    fp = fopen("out", "w");
    if (fp == NULL)
    {
        printf("error out.\n");
        exit(1);
    }

    while (i < numbers.size)
    {
        fprintf(fp, "%d,", numbers.data[i]);
        i++;
    }

    fclose(fp);
}

void cleanup()
{
    ;
}

posted @ 2022-04-01 17:19  starc的miao  阅读(46)  评论(0)    收藏  举报