Linux中的进程与线程

介绍了Linux下fork()创建进程以及使用pthread_create()创建线程的方法

1. 基于进程的斐波那契数列

在下面的代码中,由子进程进行斐波那契数列的输出,父进程要等待子进程输出完毕,然后再执行。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char* argv[])
{
    /**
     * pid用来保存fork()的返回值
     * n用来保存用户输入
     * f0,f1,f2用于计算斐波那契数列
     */
    pid_t pid;
    int i;
    int n;
    int f0, f1, f2;
    f0 = 0;
    f1 = 1;

    /**
     * 命令行参数验证
     * argv[1]表示用户输入的命令行参数,这里是5
     * 如果用户没有输入这个参数,提示用户不能为空,然后返回
     * 如果用户输入的是负数,提示用户要输入一个正数,然后返回
     * atoi()是把字符串转换为整数的方法
     */
    if (argv[1] == NULL)
    {
        fprintf(stderr, "命令行参数不能为空\n");
        exit(-1);
    }

    if (atoi(argv[1]) < 0)
    {
        fprintf(stderr, "请输入一个正数\n");
        exit(-1);
    }

    /**
     * 用fork()来创建新进程,
     * 返回值如果<0,表示进程创建失败,
     * 如果=0,表示该进程是一个子进程,
     * 否则,表示该进程是父进程  
     */
    pid = fork();

    //进程创建失败的情况,此时提示fork失败
    if (pid < 0) 
    {
        fprintf(stderr, "fork failed");
        exit(-1);
    } else if (pid == 0)
    //pid = 0表示子进程,在子进程中要完成斐波那契数列的计算输出
    {
        n = atoi(argv[1]);
        printf("参数为:%d\n", n);
        if (n == 1) {
            printf("%d ", f0);
        } else {
            printf("%d %d ", f0, f1);
            for (i = 3; i <= n; i++) {
                f2 = f0 + f1;
                f0 = f1;
                f1 = f2;
                printf("%d ", f2);
            }
        }
        printf("\n子进程执行完毕\n");
    } else {
        //此时表示父进程,父进程要先等待(wait)子进程执行完毕,然后再执行
        wait(NULL);
        printf("父进程执行完毕\n");
    }

    return 0;
}

2. 基于线程的斐波那契数列

在下面代码中,由子线程负责斐波那契数列的数据保存,父线程需要等待子线程的数据全部保存完毕,才能输出数据。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

/**
 * 该函数是一个子线程函数,在这里给斐波那契数列的数组fib赋值
 * 即在子线程中把数据算好,保存在数组fib当中
 * 由于子线程和父线程可以共享数据,所以fib在子线程结束以后还存在
 */
void *thread_fun(int *fib) 
{
    int i;
    int num = fib[0];
    fib[1] = 0;
    fib[2] = 1;

    for (i = 3; i <= num; i++) {
        fib[i] = fib[i-1] + fib[i-2];
    }

    return NULL;
}

int main(int argc, char* argv[])
{
    /**
     * ntid用来保存子线程的线程指针
     * err用来保存pthread_create的返回值
     * 定义了一个数组fib[50]用来存储斐波那契数列的数据
     * 用n来接受用户输入
     */
    pthread_t ntid;
    int err;
    int i;
    int n;
    int fib[50];

    /**
     * 命令行参数验证
     * argv[1]表示用户输入的命令行参数,这里是5
     * 如果用户没有输入这个参数,提示用户不能为空,然后返回
     * 如果用户输入的是负数,提示用户要输入一个正数,然后返回
     * atoi()是把字符串转换为整数的方法
     */
    if (argv[1] == NULL)
    {
        fprintf(stderr, "命令行参数不能为空\n");
        exit(-1);
    }
    if (atoi(argv[1]) < 0)
    {
        fprintf(stderr, "请输入一个正数\n");
        exit(-1);
    }

    /**
     * n来接收用户的输入
     * 用fib[0]来保存用户输入的数据,以方便下一步传参数
     */
    n = atoi(argv[1]);
    fib[0] = n;

    /**
     * 创建一个新的线程,第一个参数用来保存线程的指针,第二个参数设置为NULL
     * 第三个参数表示子线程要执行的函数,第四个参数为函数的参数
     * 我们把fib这个数组传过去
     */
    err = pthread_create(&ntid, NULL, thread_fun, (void *)fib);
    
    //err!=0表示线程创建失败的情况,此时提示错误
    if (err != 0) {
        fprintf(stderr, "线程创建失败\n");
        exit(-1);
    }
    //如果执行到这里,表示子线程创建成功,但是父线程需要等待子线程执行完毕
    //pthread_join()方法表示父线程要等待子线程ntid的执行,ntid是刚才创建线程时保存子线程的指针
    pthread_join(ntid,NULL);

    /**
     * 到这里表示子线程已经执行完毕了,所有数据应该都有了
     * 那么我们可以将他们打印出来了
     */
    printf("子线程执行完毕,由父线程输出数据:\n");
    for(i = 1; i<= n; i++) {
        printf("%d ", fib[i]);
    }

    printf("\n");
}
posted @ 2017-03-30 22:34  Kassadin  阅读(921)  评论(2编辑  收藏  举报