多线程排序-v33-多进程-管道通信

2022/7/14 5:20:31

本文主要是介绍多线程排序-v33-多进程-管道通信,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

makefile

v33:v33.o
	gcc -o v33 v33.o -lm -lpthread 
v33.o:v33.c
	gcc -c v33.c 
.PHONY:clean
clean:
	-rm v33
	-rm *.o
	-rm *.txt

v33.c

// 多线程排序-多进程-管道通信-V33
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <sys/resource.h>
#include <stdlib.h>
#include <unistd.h>

#define SIZE 16

struct data_size
{
    int size;
    int *data;
};

struct data_info
{
    int size;
    int *data;
};

// 注意多进程结构体的内容
struct fork_info
{
    struct data_size array;
    struct data_info *bins;
    int status;
    pid_t npid;
    int pipefd[2];  // pipe管道创建的两个文件描述符,读和写
};

// 申请内存空间
int *allocate(int size)
{
    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] = {""};

    fp = fopen(txt, "w");
    if (fp == NULL)
    {
        perror("Error print data.");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < array.size; i++)
    {
        sprintf(num_str, "%d", array.data[i]);
        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(struct data_info bin)
{
    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_back(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;
}

int main(int argc, char *argv[])
{
    // 初始化参数变量
    struct data_size array;
    struct data_info bins[4];
    struct fork_info forks[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);
    }

    // 初始数据
    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=%d.\n", sum);

    // 多进程
    for (int i = 0; i < 4; i++)
    {
        forks[i].bins = &bins[i];   // 注意使用取地址符
        if (pipe(forks[i].pipefd) < 0)   // 创建管道文件描述符,读和写
        {
            perror("Error pipe");
            exit(EXIT_FAILURE);
        }

        forks[i].npid = fork();   // 创建子进程

        if (forks[i].npid < 0)      // 创建子进程失败
        {
            perror("Error fork");
            exit(EXIT_FAILURE);
        }   
        else if (forks[i].npid == 0)    // 子进程
        {
            insertion(*forks[i].bins);  // 多进程的排序,使用的是带星号

            close(forks[i].pipefd[0]);
            write(forks[i].pipefd[1], &forks[i].bins->data[0], sizeof(int) * forks[i].bins->size);
            close(forks[i].pipefd[1]);

            _exit(EXIT_SUCCESS);
        }
        else                        // 父进程
        {
            close(forks[i].pipefd[1]);

            int pos = 0;
            int size = 0;

            while ((size = read(forks[i].pipefd[0], forks[i].bins->data + pos / sizeof(int), sizeof(int) * forks[i].bins->size)) > 0)
            {
                printf("child[%d] pipe pos=%d size=%d\n", i, pos, size);
                pos += size;
            };
            close(forks[i].pipefd[0]);
        }
    }

    // 进程同步
    for (int i = 0; i < 4; i++)
    {
        waitpid(forks[i].npid, &forks[i].status, 0);
    }

    // 转移数据从缓存区到原始数据区
    move_back(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);
}


这篇关于多线程排序-v33-多进程-管道通信的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程