进程&信号&管道实践学习记录

程序分析

exec1.c & exect2.c & exect3.c

程序代码 (以exect1.c为例,其他两个结构类似)

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

int main()
{
    char    *arglist[3];

    arglist[0] = "ls";
    arglist[1] = "-l";
    arglist[2] = 0 ;//NULL
    printf("* * * About to exec ls -l\n");
    execvp( "ls" , arglist );
    printf("* * * ls is done. bye");

    return 0;
}

运行结果:

结果显示代码“* * * ls is done. bye”没有打印出来。

原因:因为调用execvp,execlp,execv时,内核将新程序载入到当前进程,替代当前进程的代码和数据。

forkdemo1.c

程序代码:

#include    <stdio.h>
#include    <sys/types.h>
#include    <unistd.h>
int main()
{
    int ret_from_fork, mypid;
    mypid = getpid();              
    printf("Before: my pid is %d\n", mypid);
    ret_from_fork = fork();
    sleep(1);
    printf("After: my pid is %d, fork() said %d\n",
        getpid(), ret_from_fork);

    return 0;
}

运行结果:

分析:fork()在父进程中返回子进程的pid,在子进程中返回0。

forkdemo2.c

程序代码:

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

int main()
{
    printf("before:my pid is %d\n", getpid() );
    fork();
    fork();
    printf("aftre:my pid is %d\n", getpid() );

    return 0;
}

运行结果:

进程&信号&管道实践学习记录_第1张图片

分析:两次fork()共产生3个子进程,加上父进程总共有4个进程。

forkdemo3.c

程序代码:

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

int main()
{
    int fork_rv;

    printf("Before: my pid is %d\n", getpid());

    fork_rv = fork();       /* create new process   */

    if ( fork_rv == -1 )        /* check for error  */
    perror("fork");
    else if ( fork_rv == 0 ){ 
        printf("I am the child.  my pid=%d\n", getpid());

        exit(0);
    }
    else{
        printf("I am the parent. my child is %d\n", fork_rv);
        exit(0);
    }

    return 0;
}

运行效果:

forkdemo4.c

程序代码:

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

int main()
{
    int fork_rv;

    printf("Before: my pid is %d\n", getpid());

    fork_rv = fork();       /* create new process   */

    if ( fork_rv == -1 )        /* check for error  */
        perror("fork");

    else if ( fork_rv == 0 ){ 
        printf("I am the child.  my pid=%d\n", getpid());
        printf("parent pid= %d, my pid=%d\n", getppid(), getpid());
        exit(0);
    }

    else{
        printf("I am the parent. my child is %d\n", fork_rv);
        sleep(10);
        exit(0);
    }

    return 0;
}

运行结果:

forkgdb.c

程序代码:

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

int  gi=0;
int main()
{
    int li=0;
    static int si=0;
    int i=0;

    pid_t pid = fork();
    if(pid == -1){
        exit(-1);
    }
    else if(pid == 0){
        for(i=0; i<5; i++){
            printf("child li:%d\n", li++);
            sleep(1);
            printf("child gi:%d\n", gi++);
            printf("child si:%d\n", si++);
        }
        exit(0);
    
    }
    else{
        for(i=0; i<5; i++){
            printf("parent li:%d\n", li++);
            printf("parent gi:%d\n", gi++);
            sleep(1);
            printf("parent si:%d\n", si++);
        }
    exit(0);    

    }
    return 0;
}

运行效果:

进程&信号&管道实践学习记录_第2张图片

分析:运行结果说明了子进程与父进程并发运行。

psh1.c

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

#define MAXARGS     20              
#define ARGLEN      100             

//将字符串内容当做命令来执行。
int execute( char *arglist[] )
{
    execvp(arglist[0], arglist);        
    perror("execvp failed");
    exit(1);
}

char * makestring( char *buf )
{
    char    *cp;

    buf[strlen(buf)-1] = '\0';      
    cp = malloc( strlen(buf)+1 );       
    if ( cp == NULL ){          
        fprintf(stderr,"no memory\n");
        exit(1);
    }
    strcpy(cp, buf);        
    return cp;          
}

int main()
{
    char    *arglist[MAXARGS+1];        
    int     numargs;            
    char    argbuf[ARGLEN];         

    numargs = 0;
    while ( numargs < MAXARGS )
    {                   
        printf("Arg[%d]? ", numargs);
        if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' )
            arglist[numargs++] = makestring(argbuf);
        else
        {
            if ( numargs > 0 ){     
                arglist[numargs]=NULL;  
                execute( arglist ); //将arglist中的字符串当做命令来执行。
                numargs = 0;        
            }
        }
    }
    return 0;
}

运行结果:

进程&信号&管道实践学习记录_第3张图片

程序功能:输入字符串并将其当做命令执行。

psh2.c

程序代码:

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

#define MAXARGS     20              
#define ARGLEN      100             

char *makestring( char *buf )
{
    char    *cp;

    buf[strlen(buf)-1] = '\0';      
    cp = malloc( strlen(buf)+1 );       
    if ( cp == NULL ){          
        fprintf(stderr,"no memory\n");
        exit(1);
    }
    strcpy(cp, buf);        
    return cp;          
}

void execute( char *arglist[] )
{
    int pid,exitstatus;             

    pid = fork();                   
    switch( pid ){
        case -1:    
            perror("fork failed");
            exit(1);
        case 0:
            execvp(arglist[0], arglist);        
            perror("execvp failed");
            exit(1);
        default:
            while( wait(&exitstatus) != pid )
                ;
            printf("child exited with status %d,%d\n",
                    exitstatus>>8, exitstatus&0377);
    }
}

int main()
{
    char    *arglist[MAXARGS+1];        
    int     numargs;            
    char    argbuf[ARGLEN];         

    numargs = 0;
    while ( numargs < MAXARGS )
    {                   
        printf("Arg[%d]? ", numargs);
        if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' )
            arglist[numargs++] = makestring(argbuf);
        else
        {
            if ( numargs > 0 ){     
                arglist[numargs]=NULL;  
                execute( arglist ); 
                numargs = 0;        
            }
        }
    }
    return 0;
}

运行结果:

进程&信号&管道实践学习记录_第4张图片

程序功能:不断产生新的子进程输入字符串命令。

testbuf1

程序代码:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    printf("hello");
    fflush(stdout);
    while(1);
}

运行效果:

testbuf2

程序代码:

#include <stdio.h>
int main()
{
    printf("hello\n");
    while(1);
}

运行效果:

testbuf3

程序代码:

#include <stdio.h>

int main()
{
    fprintf(stdout, "1234", 5);
    fprintf(stderr, "abcd", 4);
}

运行效果:

分析:在默认情况下,stdout是行缓冲的,他的输出会放在一个buffer里面,只有到换行的时候,才会输出到屏幕。而stderr是无缓冲的,会直接输出。所以输出结果为:abcd1234

testpid.c

程序代码:

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

#include <sys/types.h>

int main()
{
    printf("my pid: %d \n", getpid());//获取当前进程pid
    printf("my parent's pid: %d \n", getppid());//获取当前进程父进程pid
    return 0;
}

运行效果:

testpp.c

程序代码:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    char **pp;
    pp[0] = malloc(20);

    return 0;
}

运行效果:

testsystem.c

程序代码:

#include    <stdlib.h>

int main ( int argc, char *argv[] )
{

    system(argv[1]);
    system(argv[2]);
    return EXIT_SUCCESS;
}       
  • system函数:

system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。 返回值 =-1:出现错误 =0:调用成功但是没有出现子进程 >0:成功退出的子进程的id 如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值>。如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。

运行效果:
进程&信号&管道实践学习记录_第5张图片

waitdemo1.c

程序代码:

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

#define DELAY   4

void child_code(int delay)
{
    printf("child %d here. will sleep for %d seconds\n", getpid(), delay);
    sleep(delay);
    printf("child done. about to exit\n");
    exit(17);
}

void parent_code(int childpid)
{
    int wait_rv=0;      /* return value from wait() */
    wait_rv = wait(NULL);//子进程成功结束返回子进程PID,没有子进程则返回-1。
    printf("done waiting for %d. Wait returned: %d\n", 
            childpid, wait_rv);
}
int main()
{
    int  newpid;
    printf("before: mypid is %d\n", getpid());
    if ( (newpid = fork()) == -1 )
        perror("fork");
    else if ( newpid == 0 )
        child_code(DELAY);
    else
        parent_code(newpid);

    return 0;
}

运行效果:

waitdemo2.c

程序代码:
#include
#include
#include <sys/types.h>
#include <sys/wait.h>
#include

#define DELAY   10

void child_code(int delay)
{
    printf("child %d here. will sleep for %d seconds\n", getpid(), delay);
    sleep(delay);
    printf("child done. about to exit\n");
    exit(27);
}

void parent_code(int childpid)
{
    int wait_rv;    
    int child_status;
    int high_8, low_7, bit_7;

    wait_rv = wait(&child_status);
    printf("done waiting for %d. Wait returned: %d\n", childpid, wait_rv);

    high_8 = child_status >> 8;     /* 1111 1111 0000 0000 */
    low_7  = child_status & 0x7F;   /* 0000 0000 0111 1111 */
    bit_7  = child_status & 0x80;   /* 0000 0000 1000 0000 */
    printf("status: exit=%d, sig=%d, core=%d\n", high_8, low_7, bit_7);
}

int main()
{
    int  newpid;

    printf("before: mypid is %d\n", getpid());

    if ( (newpid = fork()) == -1 )
        perror("fork");
    else if ( newpid == 0 )
        child_code(DELAY);
    else
        parent_code(newpid);
}

运行结果:
进程&信号&管道实践学习记录_第6张图片

argtest.c

程序代码:

#include <stdio.h>
#include <stdlib.h>
#include "argv.h"

int main(int argc, char *argv[]) {
char delim[] = " \t";
int i;
char **myargv;
   int numtokens;

   if (argc != 2) {
     fprintf(stderr, "Usage: %s string\n", argv[0]);
      return 1;
}   
if ((numtokens = makeargv(argv[1], delim, &myargv)) == -1) {
      fprintf(stderr, "Failed to construct an argument array for %s\n", argv[1]);
     return 1;
} 
printf("The argument array contains:\n");
for (i = 0; i < numtokens; i++)
      printf("%d:%s\n", i, myargv[i]);

   execvp(myargv[0], myargv);

   return 0;
}

功能:将输入字符串当做系统命令执行。

运行结果:

environ.c

程序代码:

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

int main(void)
{
    printf("PATH=%s\n", getenv("PATH"));
    setenv("PATH", "hello", 1);
    printf("PATH=%s\n", getenv("PATH"));
#if 0
    printf("PATH=%s\n", getenv("PATH"));
    setenv("PATH", "hellohello", 0);
    printf("PATH=%s\n", getenv("PATH"));


    printf("MY_VER=%s\n", getenv("MY_VER"));
    setenv("MY_VER", "1.1", 0);
    printf("MY_VER=%s\n", getenv("MY_VER"));
    #endif
    return 0;
}

运行效果:

environvar.c

运行代码:

#include <stdio.h>
int main(void)
{
    extern char **environ;
    int i;
    for(i = 0; environ[i] != NULL; i++)
        printf("%s\n", environ[i]);

    return 0;
}

功能:打印环境变量。

运行效果:
进程&信号&管道实践学习记录_第7张图片

sigactdemo.c

程序代码:

#include    <stdio.h>
#include    <unistd.h>
#include    <signal.h>
#define INPUTLEN    100
void inthandler();  
int main()
{
    struct sigaction newhandler;    
    sigset_t blocked;   
    char x[INPUTLEN];
    newhandler.sa_handler = inthandler;//新的信号处理函数效果与signal()类似  
    newhandler.sa_flags = SA_RESTART|SA_NODEFER
    |SA_RESETHAND;//设置信号处理相关操作  
    sigemptyset(&blocked);  //将blocked信号集初始化,并清空。
    sigaddset(&blocked, SIGQUIT);//将SIGQUIT信号加入参数blocked信号集。    
    newhandler.sa_mask = blocked;//暂时将block信号阻塞 
    if (sigaction(SIGINT, &newhandler, NULL) == -1)
        perror("sigaction");
    else
        while (1) {
            fgets(x, INPUTLEN, stdin);
            printf("input: %s", x);
        }
    return 0;
}
void inthandler(int s)
{
    printf("Called with signal %d\n", s);
    sleep(s * 4);
    printf("done handling signal %d\n", s);
}

sigation结构体:

struct sigaction {

void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *,  void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
  • sa_handler此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。
  • sa_mask 指定在信号处理程序执行过程中,哪些信号应当被阻塞。默认当前信号本身被阻塞。
  • sa_restorer 已过时,POSIX不支持它,不应再使用。
  • sa_flags 用来设置信号处理的其他相关操作,下列的数值可用。
  • sa_flags还可以设置其他标志:
    • SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
    • SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
    • SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号

运行效果:

sigactdemo2.c

#include <unistd.h>
#include <signal.h>
#include <stdio.h>

void sig_alrm( int signo )
{
    /*do nothing*/
}

unsigned int mysleep(unsigned int nsecs)
{
    struct sigaction newact, oldact;
    unsigned int unslept;

    newact.sa_handler = sig_alrm;//设置处理函数
    sigemptyset( &newact.sa_mask );//清空newact的阻塞信号集
    newact.sa_flags = 0;//设置信号处理的其它操作为空
    sigaction( SIGALRM, &newact, &oldact );//显式取消阻塞信号

    alarm( nsecs );//设置闹钟
    pause();

    unslept = alarm ( 0 );//取消闹钟,并返回剩余时间
    sigaction( SIGALRM, &oldact, NULL );

    return unslept;
}

int main( void )
{
    while( 1 )
    {
        mysleep( 2 );
        printf( "Two seconds passed\n" );
    }

    return 0;
}

运行效果:

进程&信号&管道实践学习记录_第8张图片

sigdemo1.c

#include    <stdio.h>
#include    <signal.h>
void    f(int);         
int main()
{
    int i;
    signal( SIGINT, f );//改变键盘ctril+C处理函数       
    for(i=0; i<5; i++ ){        
        printf("hello\n");
        sleep(2);
    }

    return 0;
}

void f(int signum)          
{
    printf("OUCH!\n");
}

运行效果:

进程&信号&管道实践学习记录_第9张图片

sigdemo2.c

#include    <stdio.h>
#include    <signal.h>

main()
{
    signal( SIGINT, SIG_IGN );//设置忽略Ctrl+C中断信号。

    printf("you can't stop me!\n");
    while( 1 )
    {
        sleep(1);
        printf("haha\n");
    }
}

运行效果:

进程&信号&管道实践学习记录_第10张图片

sigdemo3.c

程序代码:

#include    <stdio.h>
#include    <string.h>
#include    <signal.h>
#include    <unistd.h>

#define INPUTLEN    100

int main(int argc, char *argv[])
{
    void inthandler(int);
    void quithandler(int);
    char input[INPUTLEN];
    int nchars;

    signal(SIGINT, inthandler);//^C 
    signal(SIGQUIT, quithandler);//^\

    do {
        printf("\nType a message\n");
        nchars = read(0, input, (INPUTLEN - 1));
        if (nchars == -1)
            perror("read returned an error");
        else {
            input[nchars] = '\0';
            printf("You typed: %s", input);
        }
    }
    while (strncmp(input, "quit", 4) != 0);
    return 0;
}

void inthandler(int s)
{
    printf(" Received signal %d .. waiting\n", s);
    sleep(2);
    printf("  Leaving inthandler \n");
}

void quithandler(int s)
{
    printf(" Received signal %d .. waiting\n", s);
    sleep(3);
    printf("  Leaving quithandler \n");
}

运行效果:
进程&信号&管道实践学习记录_第11张图片

listargs.c

程序代码

#include    <stdio.h>

main( int ac, char *av[] )
{
    int i;

    printf("Number of args: %d, Args are:\n", ac);//ac为传入参数的个数。
    for(i=0;i<ac;i++)
        printf("args[%d] %s\n", i, av[i]);

    fprintf(stderr,"This message is sent to stderr.\n");
}

运行效果:

pipe.c

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

#define oops(m,x)   { perror(m); exit(x); }

int main(int ac, char **av)
{
    int thepipe[2],         
        newfd,              
        pid;                
    //判断管道输入格式是否正确
    if ( ac != 3 ){
        fprintf(stderr, "usage: pipe cmd1 cmd2\n");
        exit(1);
    }
    //管道建立失败,输出错误信息
    if ( pipe( thepipe ) == -1 )        
        oops("Cannot get a pipe", 1);
    //子进程创建失败,输出错误信息
    if ( (pid = fork()) == -1 )         
        oops("Cannot fork", 2);
    
    if ( pid > 0 ){         
        close(thepipe[1]);  

        if ( dup2(thepipe[0], 0) == -1 )//将thepipe[0]重定向到标准输入
            oops("could not redirect stdin",3);

        close(thepipe[0]);  
        execlp( av[2], av[2], NULL);//试着执行av[2]中的命令
        oops(av[2], 4);
    }

    close(thepipe[0]);      

    if ( dup2(thepipe[1], 1) == -1 )//将thepipe[1]重定向到标准输出
        oops("could not redirect stdout", 4);

    close(thepipe[1]);      
    execlp( av[1], av[1], NULL);//试着执行av[1]中的命令
    oops(av[1], 5);
}
  • pipe():

    1) 头文件 #include

    2) 定义函数: int pipe(int filedes[2]);

    3) 函数说明: pipe()会建立管道,并将文件描述词由参数filedes数组返回。
    filedes[0]为管道里的读取端
    filedes[1]则为管道的写入端。

    4) 返回值: 若成功则返回零,否则返回-1,错误原因存于errno中。

execlp():

从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则将它解释为整形参数,如果一个整形数的长度与char * 的长度不同,那么exec函数的实际参数就将出错。如果函数调用成功,进程自己的执行代码就会变成加载程序的代码,execlp()后边的代码也就不会执行了。

返回值:
如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。

运行效果:

进程&信号&管道实践学习记录_第12张图片

pipedemo2.c

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


#define CHILD_MESS  "I want a cookie\n"
#define PAR_MESS    "testing..\n"
#define oops(m,x)   { perror(m); exit(x); }

main()
{
    int pipefd[2];      
    int len;            
    char    buf[BUFSIZ];        
    int read_len;

    if ( pipe( pipefd ) == -1 )
        oops("cannot get a pipe", 1);

    switch( fork() ){
        case -1:
            oops("cannot fork", 2);

        case 0:         
            len = strlen(CHILD_MESS);
            while ( 1 ){
                if (write( pipefd[1], CHILD_MESS, len) != len )
                    oops("write", 3);
                sleep(5);
            }
    
        default:        
            len = strlen( PAR_MESS );
            while ( 1 ){
                if ( write( pipefd[1], PAR_MESS, len)!=len )
                    oops("write", 4);
                sleep(1);
                read_len = read( pipefd[0], buf, BUFSIZ );
                if ( read_len <= 0 )
                    break;
                write( 1 , buf, read_len );
            }
    }
}

运行结果:
进程&信号&管道实践学习记录_第13张图片

pipedemo.c

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

int main()
{
    int len, i, apipe[2];   
    char    buf[BUFSIZ];        

    if ( pipe ( apipe ) == -1 ){
        perror("could not make pipe");
        exit(1);
    }
    printf("Got a pipe! It is file descriptors: { %d %d }\n", 
                        apipe[0], apipe[1]);


    while ( fgets(buf, BUFSIZ, stdin) ){
        len = strlen( buf );
        if (  write( apipe[1], buf, len) != len ){  
            perror("writing to pipe");      
            break;                  
        }
        for ( i = 0 ; i<len ; i++ )                     
            buf[i] = 'X' ;
        len = read( apipe[0], buf, BUFSIZ ) ;       
        if ( len == -1 ){               
            perror("reading from pipe");        
            break;
        }
        if ( write( 1 , buf, len ) != len ){    //将标准输入写到标准输出   
            perror("writing to stdout");        
            break;                  
        }
    }
}

运行结果:
进程&信号&管道实践学习记录_第14张图片


stdinerdir1.c

程序代码:

#include    <stdio.h>
#include    <fcntl.h>

int main()
{
    int fd ;
    char    line[100];

    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );

    close(0);
    fd = open("/etc/passwd", O_RDONLY);//读取passwd文件到stdin
    if ( fd != 0 ){
        fprintf(stderr,"Could not open data as fd 0\n");
        exit(1);
    }

    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
}

进程&信号&管道实践学习记录_第15张图片

stdinredir2.c

#include        <stdio.h>
#include    <stdlib.h>
#include    <fcntl.h>

//#define   CLOSE_DUP       
//#define   USE_DUP2    

main()
{
    int fd ;
    int newfd;
    char    line[100];

    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );

    fd = open("data", O_RDONLY);    
#ifdef CLOSE_DUP
    close(0);
    newfd = dup(fd);        
#else
    newfd = dup2(fd,0); //将fd重定向到标准输入   
#endif
    if ( newfd != 0 ){
        fprintf(stderr,"Could not duplicate fd to 0\n");
        exit(1);
    }
    close(fd);          

    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
}

运行效果:(没有data文件,无法获取文件描述符,重定向失败)
进程&信号&管道实践学习记录_第16张图片

testtty.c

#include <unistd.h>

int main()
{
    char *buf = "abcde\n";
    write(0, buf, 6);//将字符串写到标准输入
}

运行效果:

whotofile.c

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

int main()
{
    int pid ;
    int fd;

    printf("About to run who into a file\n");

    if( (pid = fork() ) == -1 ){
        perror("fork"); exit(1);
    }
    if ( pid == 0 ){
        close(1);               /* close, */
        fd = creat( "userlist", 0644 );     /* then open *///以写的方式创建一个文件,因为前面关闭了文件描述符1,所以fd=1,为标准输出。
        execlp( "who", "who", NULL );       /* and run  *///执行who命令,输出到文件表描述符1中。
        perror("execlp");
        exit(1);
    }
    if ( pid != 0 ){
        wait(NULL);
        printf("Done running who.  results in userlist\n");
    }

    return 0;
}

运行结果:
进程&信号&管道实践学习记录_第17张图片

consumer.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_NAME "/tmp/myfifo"
#define BUFFER_SIZE PIPE_BUF


int main()
{
    int pipe_fd;
    int res;

    int open_mode = O_RDONLY;
    char buffer[BUFFER_SIZE + 1];
    int bytes = 0;

    memset(buffer, 0, sizeof(buffer));//数组置零

    printf("Process %d opeining FIFO O_RDONLY \n", getpid());
    pipe_fd = open(FIFO_NAME, open_mode);
    printf("Process %d result %d\n", getpid(), pipe_fd);

    if (pipe_fd != -1) {
        do {
            res = read(pipe_fd, buffer, BUFFER_SIZE);
            bytes += res;
        } while (res > 0);
        close(pipe_fd);
    } else {
        exit(EXIT_FAILURE);
    }

    printf("Process %d finished, %d bytes read\n", getpid(), bytes);
    exit(EXIT_SUCCESS);
}

运行效果:

文件不存在,打开失败。

文件存在读取成功。

producer.c

程序代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_NAME "/tmp/myfifo"
#define BUFFER_SIZE PIPE_BUF
#define TEN_MEG (1024 * 1024 * 10)

int main()
{
    int pipe_fd;
    int res;
    int open_mode = O_WRONLY;

    int bytes = 0;
    char buffer[BUFFER_SIZE + 1];
    //判断文件是否存在。
    if (access(FIFO_NAME, F_OK) == -1) {
        res = mkfifo(FIFO_NAME, 0777);//创建一个FIFO文件
        if (res != 0) {
            fprintf(stderr, "Could not create fifo %s \n",
            FIFO_NAME);
            exit(EXIT_FAILURE);
        }
    }

    printf("Process %d opening FIFO O_WRONLY\n", getpid());
    pipe_fd = open(FIFO_NAME, open_mode);
    printf("Process %d result %d\n", getpid(), pipe_fd);

    if (pipe_fd != -1) {
        while (bytes < TEN_MEG) {
            res = write(pipe_fd, buffer, BUFFER_SIZE);
            if (res == -1) {
                fprintf(stderr, "Write error on pipe\n");
                exit(EXIT_FAILURE);
            }
            bytes += res;
        }
        close(pipe_fd);
    } else {
        exit(EXIT_FAILURE);
    }

    printf("Process %d finish\n", getpid());
    exit(EXIT_SUCCESS);
}

access():

判断是否具有存取文件的权限
相关函数
stat,open,chmod,chown,setuid,setgid
表头文件
#include
定义函数
int access(const char * pathname, int mode);
函数说明
access()会检查是否可以读/写某一已存在的文件。参数mode有几种情况组合:
R_OK,W_OK,X_OK 和F_OK。
R_OK,W_OK与X_OK用来检查文件是否具有读取、写入和执行的权限。
F_OK则是用来判断该文件是否存在。由于access()只作权限的核查,并不理会文件形态或文件内容,因此,如果一目录表示为“可写入”,表示可以在该目录中建立新文件等操作,而非意味此目录可以被当做文件处理。例如,你会发现DOS的文件都具有“可执行”权限,但用execve()执行时则会失败。
返回值
若所有欲查核的权限都通过了检查则返回0值,表示成功,只要有一权限被禁止则返回-1。

mkfifo()

mkfifo函数的作用是在文件系统中创建一个文件(该文件之前必须不存在),该文件用于提供FIFO功能,即命名管道。前边讲的那些管道都没有名字,因此它们被称为匿名管道,或简称管道。
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo( const char *pathname, mode_t mode );
mkfifo函数需要两个参数,第一个参数(pathname)是将要在文件系统中创建的一个专用文件。第二个参数(mode)用来规定FIFO的读写权限。Mkfifo函数如果调用成功的话,返回值为0;如果调用失败返回值为-1。

运行结果:

遇到的问题及解决

1.sigactdemo.c中的inthandler中的参数int s是怎么传进去的?

进程&信号&管道实践学习记录_第18张图片

解决方法:在博客园提问。

inthandler被当做函数指针传给了newhandler.sa_handler
后面调用int sigaction(int signum,const struct sigaction act ,struct sigaction oldact);
它的第一个参数signum指定的信号编号就是用来设置这个信号的处理函数的。信号SIGINT序号为2。

命令kill -l可以查看各信号的序号。

2.运行testpp时遇到段错误(核心已转储)。
进程&信号&管道实践学习记录_第19张图片

解决方法:在博客园提问。

二维数组越界申请空间。

将代码改为

pp=malloc(20);

即可编译成功。

参考资料

《深入理解计算机系统》第8章异常控制流

你可能感兴趣的:(进程&信号&管道实践学习记录)