多线程排序-复盘
调试工具
valgrind内存泄漏检测
参考连接:
- https://zhuanlan.zhihu.com/p/75416381
- https://www.cnblogs.com/lidabo/p/4377545.html
- https://www.cnblogs.com/bokeyuan-dlam/articles/9157857.html
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()
{
;
}