makefile
v22:v22.o
gcc -o v22 v22.o -lm -lpthread
v22.o:v22.c
gcc -c v22.c
.PHONY:clean
clean:
-rm v22
-rm *.o
-rm *.txt
v22.c
// 多线程排序-v22
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#define SIZE 16
// 原始数据结构体
struct data_size
{
int size;
int *data;
};
struct data_info
{
int size;
int *data;
};
struct thread_data
{
struct data_size array; // 选择处理哪一块的数组
struct data_info *bins;
pthread_t tid;
};
// 初始化原始数据
int *allocate(int size) // 错误:struct data_size array,正确:需要申请内存空间的大小
{
int *space;
space = (int *)calloc(size, sizeof(int)); // 强制类型转换,内存的大小,每个单元的数据类型
// 防止申请内存失败
if (space == NULL)
{
perror("Error allocate.");
exit(EXIT_FAILURE);
}
return space;
}
// 生成随机数据
void produce_data(struct data_size array)
{
srand(1);
for (int i = 0; i < array.size; i++)
{
array.data[i] = rand() % 1000;
}
}
// 打印数据
void print_data(struct data_size array, char * txt)
{
FILE * fp;
//char num_str[4] = {0}; // 错误
// char num_str[4] = {'\0'}; // 方法1
// char num_str[4] = '\0'; // 方法2
// char num_str[4] ""; // 方法3
char num_str[4]; // 方法4
memset(num_str, 0, sizeof(num_str));
fp = fopen(txt, "w");
if (fp == NULL)
{
perror("Error fopen.");
exit(EXIT_FAILURE);
}
for (int i = 0; i < array.size; i++)
{
sprintf(num_str, "%d", array.data[i]); // int sprintf(char *str, const char *format, ...)
// size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
fwrite(num_str, sizeof(num_str), 1, fp);
fputc('\n', fp);
}
fclose(fp);
}
// 划分数据
void split_data(struct data_size array, struct data_info bins[]) // 参数是一个未指定大小的数组
{
for (int i = 0; i < array.size; i++)
{
int number = array.data[i];
if (number < 250)
{
bins[0].data[bins[0].size++] = number;
}
else if (number < 500)
{
bins[1].data[bins[1].size++] = number;
}
else if (number < 750)
{
bins[2].data[bins[2].size++] = number;
}
else
{
bins[3].data[bins[3].size++] = number;
}
}
}
// 排序
void *insertion(void *params)
{
struct thread_data args = *(struct thread_data *)params;
struct data_info bin = *args.bins;
for (int i = 1; i < bin.size; i++)
{
for (int j = i; j > 0; j--)
{
if (bin.data[j - 1] > bin.data[j])
{
int temp;
temp = bin.data[j];
bin.data[j] = bin.data[j - 1];
bin.data[j - 1] = temp;
}
else
{
break;
}
}
}
}
// 数据从缓存区到原始数据区
void move_data(struct data_size array, struct data_info bins[])
{
for (int bin = 0; bin < 4; bin++)
{
for (int i = 0; i < bins[bin].size; i++)
{
*array.data++ = bins[bin].data[i];
}
}
}
// 检查排序是否正确
bool is_sorted(struct data_size array)
{
bool sorted = true;
for (int i = 0; i < array.size - 1; i++) // 这里需要下表减一
{
if (array.data[i] > array.data[i+1])
{
sorted = false;
return sorted;
}
}
return sorted;
}
int main(int argc, char *argv[])
{
// 初始化参数
struct data_size array;
struct data_info bins[4]; // 为什么是4个数组?
struct thread_data threads[4];
// 设置参数量
if (argc < 2)
{
array.size = SIZE;
}
else
{
array.size = pow(2, atoi(argv[1]));
}
// 分配数据集空间
array.data = allocate(array.size);
for (int i = 0; i < 4; i++)
{
bins[i].size = 0;
bins[i].data = allocate(array.size); // 每个现成的的缓存空间都是元数据的大小,资源不浪费嘛
}
// 初始化原始数据
array.data = allocate(array.size);
produce_data(array);
print_data(array, "original.txt");
// 划分数据
split_data(array, bins);
// 计算缓存区数据量
int sum = 0;
for (int i = 0; i < 4; i++)
{
sum += bins[i].size;
}
printf("Size is:%d.\n", sum);
// 创建多线程,执行排序任务
for (int i = 0; i < 4; i++)
{
threads[i].bins = &bins[i]; // threads的bins的地址和bins的地址保持一致
if (pthread_create(&threads[i].tid, NULL, insertion, (void *)&threads[i])) // 参数传参的方式
{
perror("Error pthread_create.\n");
exit(EXIT_FAILURE);
}
}
// 多线程同步
for (int i = 0; i < 4; i++)
{
pthread_join(threads[i].tid, NULL);
}
// 打印数据
move_data(array, bins);
print_data(array, "insertion.txt");
printf(is_sorted(array) ? "sorted\n" : "not sorted\n");
// 释放内存空间
free(array.data);
for (int i = 0; i < 4; i++)
{
free(bins[i].data);
}
exit(EXIT_SUCCESS);
}