system创建一个进程,管道创建一个进程

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/time.h>
  5. #include <sched.h>
  6. int main(int argc, char **argv) {
  7. /*
  8. uid 用户id
  9. pid 进程标识id
  10. ppid 父进程标识id
  11. comm 命令
  12. tty 终端的名称
  13. stime 进程的启动时间
  14. time 进程的cpu时间
  15. ps -e 显示所有进程。
  16. -f 全格式。
  17. -h 不显示标题。
  18. -l 长格式。-w 宽输出。
  19. -a 显示终端上的所有进程,包括其他用户的进程。
  20. -r 只显示正在运行的进程。
  21. -x 显示没有控制终端的进程。
  22. */
  23. // int system(const char *comstring);
  24. // system("ps -o uid,pid,ppid,comm,tty,stime,time ");
  25. char buf[1024];
  26. FILE *p;
  27. char *cmd = "ps -f";
  28. // 使用管道创建一个进程
  29. // FILE *popen(const char *cmd, const char *type); type支持"r","w" 读写
  30. //
  31. if ((p = popen(cmd, "r")) == NULL)
  32. {
  33. printf("popen error!");
  34. exit(1);
  35. }
  36. // int pclose(File *stream);
  37. while(fgets(buf, sizeof(buf), p)) {
  38. printf("%s", buf);
  39. }
  40. pclose(p);
  41. pid_t pid, ppid, pgid;
  42. // pid_t getpid(void); 获取pid
  43. pid = getpid();
  44. // pid_t getppid(void); 获取ppid
  45. ppid = getppid();
  46. // pid_t getpgid(pid_t pid); // 如果pid=0返回当前进程的组标识符,如果是其他值,返回指定pid的组标识符号
  47. pgid = getpgid(0); // pid_t getpgrp(void); 相当于getpgid(0);
  48. uid_t uid = getuid();
  49. // 获取该进程,进程组,以及用户的进程允许优先级
  50. // int getpriority(int which, int who);
  51. // 函数有两个入参,which取值为PRIO_PROCESS,PRIO_PGRP,PRIO_USER;
  52. // 参数 who 根据which的值确定其具体含义,分别对应进程标识符,进程组标识符,或用户标识符
  53. // 函数运行成功返回当前进程的优先级,其值介于-20~20之间,值越小代表优先级越高。
  54. // 如果函数执行出错返回-1,错误原因存在变量errno之中
  55. int priority = getpriority(PRIO_USER, uid); // 我的uid是501,所以我填写501
  56. printf("pid=%d,ppid=%d,pgid=%d,uid=%d,priority=%d\n", pid, ppid, pgid, uid, priority);
  57. return 0;
  58. }

wait 的使用

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h> /**包含相关函数头文件*/
  4. #include <sys/time.h>
  5. #include <sched.h>
  6. int main(int argc, char **argv)
  7. {
  8. // 复制当前进程的内容,产生一个新的进程,调用fork函数的进程是父进程,所产生的进程是子进程
  9. // pid_t fork(void);
  10. pid_t pid = fork();
  11. int sta, i = -1;
  12. if (pid < 0)
  13. {
  14. printf("创建子进程失败!\n");
  15. exit(1);
  16. }
  17. if (pid == 0)
  18. {
  19. printf("这是一个子进程 pid=%d\n", getpid());
  20. // 使用这种方式,子进程是正常结束的
  21. // exit(100);
  22. // 使用这个的时候,父进程获取子进程结束状态时,会知道子进程是因为信号终止的
  23. abort();
  24. }
  25. else
  26. {
  27. printf("父进程pid=%d\n", getpid());
  28. // 暂停1s
  29. // unsigned int sleep(unsigned int seconds);
  30. sleep(1);
  31. printf("这是一个父进程\n");
  32. // pid_t wait(int *status); 函数会暂停当前进程的运行。直到有信号到来或子进程结束
  33. // 如果调用时子进程已经结束,则函数立刻返回,返回值为子进程pid,子进程结束状态由*status返回。
  34. if (pid != wait(&sta))
  35. {
  36. printf("等待子进程错误。\n");
  37. exit(1);
  38. }
  39. if (WIFSIGNALED(sta)) { // WIFSIGNALED 如果子进程是因为信号而结束的,返回真
  40. i = WTERMSIG(sta); // 如果WIFSIGNALED(status)返回值为真,返回引起终止的信号代码
  41. printf("子进程是由信号结束的\n");
  42. }
  43. // WIFEXITED 正常结束返回非0值
  44. if (WIFEXITED(sta))
  45. { // 判断进程是否为正常结束
  46. i = WEXITSTATUS(sta); // 返回状态值 WEXITSTATUS(sta)状态为真时,返回状态值低8位
  47. printf("子进程是正常结束的\n");
  48. }
  49. // 输出子进程标识符
  50. printf("子进程pid=%d\n", pid);
  51. // 输出子进程结束状态值
  52. printf("exit status=%d\n", i); // exit status=0
  53. }
  54. return 0;
  55. }

waitpid 的使用

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. //waitpid()使用示例
  5. int main(void)
  6. {
  7. pid_t pid, ret;
  8. int status = -1;
  9. printf("main process pid = %d\n", getpid());
  10. pid = fork(); //创建子进程
  11. if (pid < 0)
  12. {
  13. printf("error fork\n");
  14. exit(1);
  15. }
  16. if (pid == 0) //子进程
  17. {
  18. printf("child process pid = %d\n", getpid());
  19. printf("------------------\n");
  20. sleep(5);
  21. exit(0);
  22. }
  23. if (pid > 0) //父进程
  24. {
  25. // pid_t waitpid(pid_t pid, int *status, int option); // 这里的pid_t pid 为欲要等待的子进程标识符
  26. // option 的取值范围
  27. // WNOHANG 如果没有任何已经结束的子进程,则立即返回
  28. // WUNTRACED 如果子程序进入暂停状态,则立即返回
  29. // waitpid(...)和wait(...)函数的区别,wait阻塞调用进程直到至少有一个子进程结束,waitpid则可以选择不阻塞立即返回
  30. printf("这是父进程");
  31. // waitpid(pid, &sta, WNOHANG); // 这里没有阻断
  32. // waitpid(pid, &sta, WUNTRACED); // 这里阻断,先执行子进程在执行父进程
  33. do
  34. {
  35. // 调用waitpid,且父进程不阻塞
  36. ret = waitpid(pid, &status, WNOHANG);
  37. //若子进程还没有退出,则父进程暂停1s
  38. //等待时候执行下面语句
  39. if (ret == 0)
  40. {
  41. printf("the child process has no exited\n");
  42. sleep(1);
  43. }
  44. if (WIFSTOPPED(status)) {
  45. int i = WSTOPSIG(status); // WIFSTOPPED结果为真
  46. printf("子进程处于暂停状态 status=%d\n", status);
  47. }
  48. } while (ret == 0);
  49. //子进程退出
  50. if (pid == ret) //ret>0
  51. {
  52. printf("child process exited\n");
  53. } else {
  54. printf("some error occured.\n");
  55. }
  56. }
  57. /*
  58. main process pid = 26713
  59. the child process has no exited
  60. child process pid = 26714
  61. ------------------
  62. 子进程处于暂停状态 status=-1
  63. the child process has no exited
  64. 子进程处于暂停状态 status=-1
  65. the child process has no exited
  66. 子进程处于暂停状态 status=-1
  67. the child process has no exited
  68. 子进程处于暂停状态 status=-1
  69. the child process has no exited
  70. 子进程处于暂停状态 status=-1
  71. child process exited
  72. */
  73. }
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h> /**包含相关函数头文件*/
  4. #include <sys/time.h>
  5. #include <sched.h>
  6. int main(int argc, char **argv)
  7. {
  8. // 复制当前进程的内容,产生一个新的进程,调用fork函数的进程是父进程,所产生的进程是子进程
  9. // pid_t fork(void);
  10. pid_t pid = fork();
  11. int sta, i = -1;
  12. pid_t temp = 0;
  13. if (pid < 0)
  14. {
  15. printf("创建子进程失败!\n");
  16. exit(1);
  17. }
  18. if (pid == 0)
  19. {
  20. printf("这是一个子进程 pid=%d\n", getpid());
  21. sleep(5); // 这里进程暂停了,但是没有切换父进程执行
  22. printf("这是一个子进程 pid=%d\n", getpid());
  23. exit(0);
  24. } else {
  25. printf("这是父进程\n");
  26. temp = waitpid(pid, &sta, WUNTRACED); // 这里堵塞当前进程,必须等待子程序结束
  27. printf("%d\n", temp);
  28. if (pid != temp)
  29. {
  30. printf("等待子进程错误。\n");
  31. exit(1);
  32. }
  33. // 如果子进程处于暂停执行情况则此宏值为真。一般只有使用 WUNTRACED 时才会有此情况。
  34. if (WIFSTOPPED(sta))
  35. { // WIFSTOPPED 如果子程序处于暂停状态,返回值为真
  36. i = WSTOPSIG(sta); // WIFSTOPPED结果为真
  37. printf("子进程处于暂停状态");
  38. }
  39. // 输出子进程标识符
  40. printf("子进程pid=%d\n", pid);
  41. // 输出子进程结束状态值
  42. printf("exit status=%d\n", i); // exit status=0
  43. }
  44. /*
  45. 这是父进程
  46. 这是一个子进程 pid=27169
  47. 这是一个子进程 pid=27169
  48. 27169
  49. 子进程pid=27169
  50. exit status=-1
  51. */
  52. return 0;
  53. }

写时拷贝

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h> /**包含相关函数头文件*/
  4. #include <sys/time.h>
  5. #include <sched.h>
  6. int i = 1;
  7. void child_process() {
  8. printf("子进程:%d i=%d \n", getpid(), i); // 输出1
  9. i++; // 当它改变了i的值时,会有进行写时拷贝,会有自己的i变量,不会影响父进程
  10. printf("子进程:%d i=%d \n", getpid(), i); // 输出2
  11. }
  12. int main(int argc, char **argv)
  13. {
  14. pid_t pid;
  15. int status;
  16. // 复制进程,但是它会有自己的空间
  17. pid = fork();
  18. if (pid < 0) {
  19. printf("创建进程失败");
  20. exit(1);
  21. }
  22. if (pid == 0) {
  23. child_process();
  24. } else {
  25. sleep(1);
  26. printf("父进程:%d i=%d \n", getpid(), i); // 输出1
  27. if (pid != wait(&status)) {
  28. printf("等待子进程失败");
  29. exit(1);
  30. }
  31. }
  32. return 0;
  33. }

exec

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h> /**包含相关函数头文件*/
  4. #include <sys/time.h>
  5. #include <sched.h>
  6. int main(int argc, char **argv)
  7. {
  8. // vfork函数与fork函数的区别,vfork保证子进程先运行,在他exec或exit之后,父进程才可能被调度
  9. // 如果在调用这两个函数之前,子进程的执行依赖父进程的进一步执行,则会导致死锁。
  10. // pid_t pid = vfork(); vfork已经被废弃了,要求使用。
  11. // warning: 'vfork' is deprecated: Use posix_spawn or fork [-Wdeprecated-declarations]
  12. execlp("ps", "ps", "-o", "pid,ppid,comm", NULL);
  13. // exec 函数有6种不同形式,统称exec函数族,他们一般形式为:
  14. // int execl(const char *path, const char *arg, ...);
  15. // int execlp(const char *file, const char *arg, ...);
  16. // int execle(const char *path, const char *arg, ..., char *const envp[]);
  17. // int execv(const char *path, const char *arv[], ...);
  18. // int execvp(const char *file, const char *arv[], ...);
  19. // int execve(const char *path, const char *arv[], ..., char *const envp[]);
  20. // char *argv[] = {"full path", "param1", "param2", ..., NULL};
  21. // char *envp[] = {"name1=val1", "name2=val2", ..., NULL};
  22. // envp 指定新环境的环境变量
  23. return 0;
  24. }

终止进程

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h> /**包含相关函数头文件*/
  4. int main(int argc, char **argv)
  5. {
  6. printf("Linux C\n");
  7. printf("特别棒");
  8. // exit(1);
  9. // void _exit(int status); 他直接使进程停止运行,清除其使用的内存空间
  10. // exit函数是在_exit函数上进行了一些包装,它还会检查文件打开状态,清理I/O缓冲操作等,例如把文件缓冲系统的内容写回文件。
  11. _exit(1);
  12. // abort异常终止进程函数
  13. return 0;
  14. }

守护进程

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h> /**包含相关函数头文件*/
  4. #include <signal.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. int main(int argc, char **argv)
  8. {
  9. // 创建守护进程
  10. // 将子进程放入后台运行,就说创建守护进程的第一步,在创建过程中调用fork函数创建一个子进程,并把父进程杀死,
  11. // 使子进程进入后台执行,进而断开子进程与控制终端的关联
  12. // 在Linux中,父进程先于子进程退出会使子进程成为孤儿进程,而当系统发现孤儿进程之后,会自动由init进程(PID为1)收养它,
  13. // 这样原先子进程就会变成init的子进程
  14. pid_t pid;
  15. FILE *fp;
  16. char *buf = "这是一个示例程序\n";
  17. pid = fork();
  18. if (pid < 0) {
  19. printf("创建子进程失败");
  20. exit(1);
  21. }
  22. if (pid > 0) {
  23. // 结束父进程
  24. exit(0);
  25. }
  26. // pid_t setsid(void); // 创建新会话
  27. setsid();
  28. int filesize = 1024;
  29. int i = 0;
  30. for (i = 0; i < filesize; i++) {
  31. // 子进程会继承父进程打开的文件描述符,在这里子进程全部关掉
  32. close(i);
  33. }
  34. // 切换目录
  35. chdir("/tmp");
  36. // 重设文件权限掩码
  37. // 守护进程的文件掩码是从创建它的父进程哪里继承下来的,这会给守护进程使用文件带来诸多麻烦。为此,
  38. // 有必要将文件的权限掩码设置为0,进而增强守护进程的灵活性。
  39. umask(0);
  40. // 处理SIGCHLD信号
  41. // 对于某些进程,尤其是服务器进程,往往在请求到来时,创建子进程处理请求,而父进程则保持循环,
  42. // 以接收更多客户连接,在这种情况下,如果父进程等待子进程结束,将增加父进程的负担,
  43. // 进而会影响服务器的并发性能;如果父进程不等待子进程结束,子进程将会变成僵尸进程(zombie),继续占有系统资源。
  44. // 在Linux系统中,有几种方式可以绕过这些问题,其中最简单的方法就是,将SIGCHLD信号的操作设置为SIG_IGN
  45. signal(SIGCHLD, SIG_IGN);
  46. while(1) {
  47. fp = fopen("/tmp/test", "a");
  48. if (fp == NULL) {
  49. perror("打开文件失败!");
  50. exit(1);
  51. }
  52. fputs(buf, fp);
  53. fclose(fp);
  54. sleep(1);
  55. }
  56. return 0;
  57. }

守护进程,打印日志

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h> /**包含相关函数头文件*/
  4. #include <signal.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <time.h>
  8. #include <syslog.h>
  9. int main(int argc, char **argv)
  10. {
  11. // 创建守护进程
  12. // 将子进程放入后台运行,就说创建守护进程的第一步,在创建过程中调用fork函数创建一个子进程,并把父进程杀死,
  13. // 使子进程进入后台执行,进而断开子进程与控制终端的关联
  14. // 在Linux中,父进程先于子进程退出会使子进程成为孤儿进程,而当系统发现孤儿进程之后,会自动由init进程(PID为1)收养它,
  15. // 这样原先子进程就会变成init的子进程
  16. pid_t pid;
  17. FILE *fp;
  18. char *buf = "这是一个示例程序\n";
  19. pid = fork();
  20. if (pid < 0) {
  21. printf("创建子进程失败");
  22. exit(1);
  23. }
  24. if (pid > 0) {
  25. // 结束父进程
  26. exit(0);
  27. }
  28. // pid_t setsid(void); // 创建新会话
  29. setsid();
  30. int filesize = 1024;
  31. int i = 0;
  32. for (i = 0; i < filesize; i++) {
  33. // 子进程会继承父进程打开的文件描述符,在这里子进程全部关掉
  34. close(i);
  35. }
  36. // 切换目录
  37. chdir("/");
  38. // 重设文件权限掩码
  39. // 守护进程的文件掩码是从创建它的父进程哪里继承下来的,这会给守护进程使用文件带来诸多麻烦。为此,
  40. // 有必要将文件的权限掩码设置为0,进而增强守护进程的灵活性。
  41. umask(0);
  42. // 处理SIGCHLD信号
  43. // 对于某些进程,尤其是服务器进程,往往在请求到来时,创建子进程处理请求,而父进程则保持循环,
  44. // 以接收更多客户连接,在这种情况下,如果父进程等待子进程结束,将增加父进程的负担,
  45. // 进而会影响服务器的并发性能;如果父进程不等待子进程结束,子进程将会变成僵尸进程(zombie),继续占有系统资源。
  46. // 在Linux系统中,有几种方式可以绕过这些问题,其中最简单的方法就是,将SIGCHLD信号的操作设置为SIG_IGN
  47. signal(SIGCHLD, SIG_IGN);
  48. time_t now;
  49. while(1) {
  50. time(&now);
  51. // void syslog(int priority, char *format, ...)
  52. // 写入到/var/log/syslog文件中
  53. syslog(LOG_USER|LOG_INFO, "Current time:\t%s\t\t\n", ctime(&now));
  54. sleep(1);
  55. }
  56. return 0;
  57. }

进程通信

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <sys/wait.h>
  6. #define BUFSIZE 256
  7. int main(int argc, char **argv)
  8. {
  9. // 父进程向子进程,单向传递数据
  10. pid_t cpid;
  11. int fifod[2];
  12. int sta;
  13. char buf[BUFSIZE] = "Linux C is very good!";
  14. // 创建匿名管道
  15. // int pipe(int fd[2]);
  16. if (pipe(fifod) < 0) {
  17. printf("pipe error.\n");
  18. exit(1);
  19. }
  20. cpid = fork();
  21. if (cpid < 0) {
  22. printf("fork error.\n");
  23. exit(1);
  24. }
  25. if (cpid == 0) {
  26. close(fifod[0]); // 写入时,要关闭读端
  27. write(fifod[1], buf, sizeof(buf));
  28. } else {
  29. close(fifod[1]);
  30. read(fifod[0], buf, sizeof(buf)); // 读取时,要关闭写端
  31. printf("buf=%s\n", buf);
  32. if (cpid != wait(&sta)) {
  33. printf("wait error.\n");
  34. exit(1);
  35. }
  36. }
  37. return 0;
  38. }