程序员

Linux-创建进程与线程用到的函数解析

2017-11-03  本文已影响0人  Yojiaku

Linux-创建进程与线程用到的函数解析

【1】exit:

/*
 测试exit函数与return函数的不同
*/
#include <stdio.h>
#include <stdlib.h>

void exitExample();

void exitExample()
{
    int i = 0;
    if(i==0)
        exit(0);
}

int main()
{
    // 调用一个函数,测试其用exit是否还会返回到main函数
    exitExample();
    printf("看来在调用的函数中使用exit也能返回到调用这个函数的父函数来.\n");
    return 0;
}

the result:

yangruo@Y700:~/workspace/processTrain/shiyan1$ ./exitExample
yangruo@Y700:~/workspace/processTrain/shiyan1$ 

发现确实是直接结束了,说明推测是正确的!
新的问题又来了:如果是子进程呢?会不会直接退出整个程序?

/*
 *测试在子进程中使用exit,是否会直接退出整个程序
 */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

void childFunc();

void childFunc()
{
    printf("这是子进程,他的PID是%d, 他的父进程PID是%d.\n", getpid(), getppid());
    exit(0);
}

int main()
{
    printf("这是main函数,也就是1号进程,他的PID是%d,他的父进程PID是%d.\n", getpid(), getppid());
    // 创建一个子进程
    pid_t child;
    child = fork();
    if(child == 0){
        // 说明创建子进程成功
        // 子进程执行一个任务
        childFunc(); 
    }else if(child < 0){
        puts("进程创建失败\n");
        exit(1);
    }else if(child > 0){
        printf("真的会输出吗?\n");
        printf("如果输出了的话就打印PID瞧瞧是哪个进程!\n");
        printf("现在这个进程PID是%d.\n", getpid());
    }
    /*
     发现一个有趣的问题:若直接是else,而不是else if(child < 0),那么else里面的语句依旧会被输出,后来找到原因:
     这是逻辑有问题,直接else的话,程序不知道这是在说child的其他值。
     !!!
     NO,测试了else if(child > 0),发现里面的语句还是会输出!所以这并不是逻辑出错了,if else语句是知道指的是child
     这个变量的!
     哦哦!原来fork()是个神奇的函数!他仅仅被调用了一次,却能返回两次,更多见注释【2】fork
    */
    // 父进程等待子进程退出
    pid_t cpid = wait(NULL); // 【5】
    printf("子进程%d已经退出.\n", cpid);
    // 父进程自己退出
    printf("父进程%d退出,程序终止\n", getpid());
    return 0;
}

【2】fork

clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fa8e369f9d0) = 3252

【3】pthread_create()第二个参数
pthread_create()的第二个参数是设置线程的属性,这些属性主要包括绑定属性(SCS、PCS)、分离属性、堆栈地址、堆栈大小、优先级。其中系统默认是非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。若把第二个参数设置为NULL的话,将采用系统默认的属性配置。

上面的属性都是通过一些函数完成的,通常先调用pthread_attr_init来初始化,之后调用相应的属性设置函数。

  1. pthread_attr_init
    功能:对线程数形变量的初始化
    头文件:<pthread.h>
    函数原型:int pthread_attr_init(pthread_attr_t *arr);
    函数传入值:attr(线程属性)
    函数返回值:成功返回0,失败返回-1
  2. pthread_attr_setscope
    功能:设置线程绑定属性
    头文件:<pthread.h>
    函数原型:int pthread_attr_setscope(pthread_attr_t *attr, int scope);
    函数传入值:attr(线程属性);scope:PTHREAD_SCOPE_SYSTEM(绑定),PTHREAD_SCOPE_PROCESS(非绑定)
    函数返回值:同1
  3. pthread_attr_setdetachstate
    功能:设置线程分离属性
    头文件:<pthread.h>
    函数原型:int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
    函数传入值:attr(线程属性),detachstate:PTHREAD_CREATE_DETACHED(分离),PTHREAD_CREATE_JOINABLE(非分离)
    函数返回值:同1
  4. pthread_attr_getschedparam
    功能: 得到线程优先级。
    头文件: <pthread.h>
    函数原型: int pthread_attr_getschedparam (pthread_attr_t* attr, struct sched_param* param);
    函数传入值:attr:线程属性;
    param:线程优先级;
    函数返回值:同1
  5. pthread_attr_setschedparam
    功能: 设置线程优先级。
    头文件: <pthread.h>
    函数原型: int pthread_attr_setschedparam (pthread_attr_t* attr, struct sched_param* param);
    函数传入值:attr:线程属性。
    param:线程优先级。
    函数返回值:同1

pthAttrExa.c

/*测试线程属性*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *pthread_func_1();
void *pthread_func_2();

void *pthread_func_1()
{
    int i = 0;
    for(; i<6; i++)
    {
        printf("This is pthread_1.\n");

        if(i == 2)
        {
            pthread_exit(0);
        }
    }
}

void *pthread_func_2()
{
    int i = 0;
    for(; i<3; i++)
    {
        printf("This is pthread_2.\n");
    }
}

int main()
{
    pthread_t pt_1 = 0;
    pthread_t pt_2 = 0;
    pthread_attr_t attr = {0};
    int ret = 0;

    pthread_attr_init(&attr); // 属社设置
    //pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    ret = pthread_create(&pt_1, &attr, pthread_func_1, NULL);
    if(ret != 0)
    {
        printf("创建线程失败\n");
    }

    ret = pthread_create(&pt_2, NULL, pthread_func_2, NULL);
    if(ret != 0)
    {
        printf("创建线程失败\n");
    }

    int ret2;
    ret2 = pthread_join(pt_2, NULL);
    if(ret2 == 0)
        printf("线程2已经结束\n");
    else
        printf("线程2没有结束,错误号%d", ret2);

    int ret1;
    ret1 = pthread_join(pt_1, NULL);
    if(ret1 == 0)
        printf("线程1已经结束\n");
    else
        printf("线程1没有结束,错误号%d\n", ret1);
    return 0;
}

the result:

$ ./pthAttrExaThis is pthread_1.
This is pthread_1.
This is pthread_1.
This is pthread_2.
This is pthread_2.
This is pthread_2.
线程2已经结束
线程1没有结束,错误号22

【4】pthread_join()
函数原型:int pthread_join(pthread_t thread, void **retval);
头文件:<pthread.h>
参数:

返回值:0代表成功,失败返回错误号
功能:以阻塞的方式等待thread指定的线程结束,当函数返回时,被等待线程的资源被收回。如果进程已经结束,那么该函数会立即返回,并且thread指定的线程必须是JOINABLE的。
注意:

【4`】pthread_exit()
函数原型:void pthread_exit(void *retval);
头文件:<pthread.h>
参数:
retval:pthread_exit()调用线程的返回值,可以用pthread_join()函数来检索获取。(只有当线程状态是非分离属性时才能正常得到这个值)
功能:退出线程。
注意:

ptrExitJoin.c

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

void assisthread(void*arg)
{
   printf("I am helping to do some jods\n");
   //sleep(3);
   printf("pthreadID:%lu\n",pthread_self());
   //pthread_exit(0);
}

int main()
{
   pthread_t assistthid;
   int status = 0;
  // pthread_attr_t attr = {0};

  // pthread_attr_init(&attr); // 属社设置
  // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
   printf("main pthreadID:%lu\n",pthread_self());
  // pthread_create(&assistthid,&attr,(void*)assisthread,NULL);
   pthread_create(&assistthid,NULL,(void*)assisthread,NULL);
   printf("create pthreadID:%lu\n",assistthid);
   pthread_join(assistthid,(void*)&status);//等待线程assisthread结束
   printf("assistthid's exit is caused %d\n",status);
   
   return 0;
}

【5】wait
头文件:<sys/types.h> <sys/wait.h>
函数原型:pid_t wait(int *status)
函数说明:wait()会暂时停止目前进程的执行, 直到有信号来到或子进程结束. 如果在调用wait()时子进程已经结束, 则wait()会立即返回子进程结束状态值. 子进程的结束状态值会由参数status 返回, 而子进程的进程识别码也会一快返回. 如果不在意结束状态值, 则参数 status 可以设成NULL. 子进程的结束状态值请参考waitpid().
传入值:status是一个整型变量指针,是该子进程退出的状态。若status不为NULL,则通过它可以获得子进程的结束状态。另外,子进程的结束状态可由Linux中一些特殊的宏来测试。
返回值:如果执行成功则返回子进程识别码(PID),如果有错误返回-1,失败原因在errno中。

上一篇下一篇

猜你喜欢

热点阅读