当前位置:   article > 正文

简明Linux系统编程教程_linux编程教程

linux编程教程

目录

01进程线程概念

02 进程创建函数

03 进程并发

04 进程监控

05 创建线程函数

06 多线程以及线程间的共享

07 进程通信——无名管道

08 测量无名管道的大小

09 无名管道进程通信实例

10 管道双向传输

11 有名管道

12 共享内存


01进程线程概念

程序:(静态的概念)
        源代码
        指令

进程:(动态的概念)
        运行着的程序
        创建销毁 耗费资源大
        进程间独立
        多个进程可以是一个程序
        由内核定义 抽象的实体  开辟一系列资源
                内部的数据结构
                内存
                进程的状态信息
        有id号

任务:
        具体要做的事情
        进程做或线程做

为什么引入线程?
        当要完成一项任务,进程被内核创建 结束时资源被内核回收 进程销毁。这段过程十分地浪费cpu资源 会给liunx系统内核带来非常大的系统消耗。

线程:
        由进程创建 速度比创建进程快
        线程从属于进程,一个进程可以有多个线程
        线程之间共享进程的资源
        某一个线程崩溃 其他会受到影响
        创建销毁线程 耗费资源小

一个程序可以创建多个进程
        每个进程做一件事情
多个进程也可以调用同一个程序
        属调用的资源

实践 获取进程pid

     pid = process id

查看getpid的用户手册

man getpid 

  1. GETPID(2) Linux Programmer's Manual GETPID(2)
  2. NAME
  3. getpid, getppid - get process identification
  4. SYNOPSIS
  5. #include <sys/types.h>
  6. #include <unistd.h>
  7. pid_t getpid(void);
  8. pid_t getppid(void);
  9. DESCRIPTION
  10. getpid() returns the process ID (PID) of the calling process. (This is
  11. often used by routines that generate unique temporary filenames.)
  12. getppid() returns the process ID of the parent of the calling process.
  13. This will be either the ID of the process that created this process using
  14. fork(), or, if that process has already terminated, the ID of the process
  15. to which this process has been reparented (either init(1) or a "subreaper"
  16. process defined via the prctl(2) PR_SET_CHILD_SUBREAPER operation).
  17. ERRORS
  18. These functions are always successful.
  19. CONFORMING TO
  20. POSIX.1-2001, POSIX.1-2008, 4.3BSD, SVr4.
  21. NOTES
  22. If the caller's parent is in a different PID namespace (see pid_name‐
  23. spaces(7)), getppid() returns 0.
  24. From a kernel perspective, the PID (which is shared by all of the threads
  25. in a multithreaded process) is sometimes also known as the thread group ID
  26. (TGID). This contrasts with the kernel thread ID (TID), which is unique
  27. for each thread. For further details, see gettid(2) and the discussion of
  28. the CLONE_THREAD flag in clone(2).
  29. C library/kernel differences
  30. From glibc version 2.3.4 up to and including version 2.24, the glibc wrap‐
  31. per function for getpid() cached PIDs, with the goal of avoiding addi‐
  32. tional system calls when a process calls getpid() repeatedly. Normally
  33. this caching was invisible, but its correct operation relied on support in
  34. the wrapper functions for fork(2), vfork(2), and clone(2): if an applica‐
  35. tion bypassed the glibc wrappers for these system calls by using
  36. syscall(2), then a call to getpid() in the child would return the wrong
  37. value (to be precise: it would return the PID of the parent process). In
  38. addition, there were cases where getpid() could return the wrong value
  39. even when invoking clone(2) via the glibc wrapper function. (For a dis‐
  40. cussion of one such case, see BUGS in clone(2).) Furthermore, the com‐
  41. plexity of the caching code had been the source of a few bugs within glibc
  42. over the years.
  43. Because of the aforementioned problems, since glibc version 2.25, the PID
  44. cache is removed: calls to getpid() always invoke the actual system call,
  45. rather than returning a cached value.
  46. On Alpha, instead of a pair of getpid() and getppid() system calls, a sin‐
  47. gle getxpid() system call is provided, which returns a pair of PID and
  48. parent PID. The glibc getpid() and getppid() wrapper functions transpar‐
  49. ently deal with this. See syscall(2) for details regarding register map‐
  50. ping.
  51. SEE ALSO
  52. clone(2), fork(2), gettid(2), kill(2), exec(3), mkstemp(3), tempnam(3),
  53. tmpfile(3), tmpnam(3), credentials(7), pid_namespaces(7)
  54. COLOPHON
  55. This page is part of release 5.10 of the Linux man-pages project. A de‐
  56. scription of the project, information about reporting bugs, and the latest
  57. version of this page, can be found at
  58. https://www.kernel.org/doc/man-pages/.
  59. Linux 2020-11-01 GETPID(2)

getpid() 当前进程
getppid() 父进程

getpid代码示例01.1

  1. #include<sys/types.h>
  2. #include<unistd.h>
  3. #include<stdio.h>
  4. int main(void)
  5. {
  6. pid_t pid;
  7. while(1)
  8. {
  9. printf("pid=%d\n",getpid());
  10. printf("ppid=%d\n",getppid());
  11. printf("hello world\n");
  12. sleep(1);
  13. }
  14. return 0;
  15. }

--gcc pid.c

--./a.out      //分析结果

 打开终端运行命令查看进程数

# pstree -p

总的来看 a.out的进程树

Systemd(1)——systemd(2578)——gnome-terminal-(9474)——bash(9492)——a.out(19740)

systemd(1):所有进程的父进程

=init(1)(历史)(一回事)

02 进程创建函数

使用fork创建进程

查看手册man  fork()

  1. FORK(2) Linux Programmer's Manual FORK(2)
  2. NAME
  3. fork - create a child process
  4. SYNOPSIS
  5. #include <sys/types.h>
  6. #include <unistd.h>
  7. pid_t fork(void);
  8. DESCRIPTION
  9. fork() creates a new process by duplicating the calling process. The new process is referred to
  10. as the child process. The calling process is referred to as the parent process.
  11. The child process and the parent process run in separate memory spaces. At the time of fork()
  12. both memory spaces have the same content. Memory writes, file mappings (mmap(2)), and unmappings
  13. (munmap(2)) performed by one of the processes do not affect the other.
  14. The child process is an exact duplicate of the parent process except for the following points:
  15. * The child has its own unique process ID, and this PID does not match the ID of any existing
  16. process group (setpgid(2)) or session.
  17. * The child's parent process ID is the same as the parent's process ID.
  18. * The child does not inherit its parent's memory locks (mlock(2), mlockall(2)).
  19. * Process resource utilizations (getrusage(2)) and CPU time counters (times(2)) are reset to
  20. zero in the child.
  21. * The child's set of pending signals is initially empty (sigpending(2)).
  22. * The child does not inherit semaphore adjustments from its parent (semop(2)).
  23. * The child does not inherit process-associated record locks from its parent (fcntl(2)). (On
  24. the other hand, it does inherit fcntl(2) open file description locks and flock(2) locks from
  25. its parent.)
  26. * The child does not inherit timers from its parent (setitimer(2), alarm(2), timer_create(2)).
  27. * The child does not inherit outstanding asynchronous I/O operations from its parent
  28. (aio_read(3), aio_write(3)), nor does it inherit any asynchronous I/O contexts from its parent
  29. (see io_setup(2)).
  30. The process attributes in the preceding list are all specified in POSIX.1. The parent and child
  31. also differ with respect to the following Linux-specific process attributes:
  32. * The child does not inherit directory change notifications (dnotify) from its parent (see the
  33. description of F_NOTIFY in fcntl(2)).
  34. * The prctl(2) PR_SET_PDEATHSIG setting is reset so that the child does not receive a signal
  35. when its parent terminates.
  36. * The default timer slack value is set to the parent's current timer slack value. See the de‐
  37. scription of PR_SET_TIMERSLACK in prctl(2).
  38. * Memory mappings that have been marked with the madvise(2) MADV_DONTFORK flag are not inherited
  39. across a fork().
  40. * Memory in address ranges that have been marked with the madvise(2) MADV_WIPEONFORK flag is ze‐
  41. roed in the child after a fork(). (The MADV_WIPEONFORK setting remains in place for those ad‐
  42. dress ranges in the child.)
  43. * The termination signal of the child is always SIGCHLD (see clone(2)).
  44. * The port access permission bits set by ioperm(2) are not inherited by the child; the child
  45. must turn on any bits that it requires using ioperm(2).
  46. Note the following further points:
  47. * The child process is created with a single thread—the one that called fork(). The entire vir‐
  48. tual address space of the parent is replicated in the child, including the states of mutexes,
  49. condition variables, and other pthreads objects; the use of pthread_atfork(3) may be helpful
  50. for dealing with problems that this can cause.
  51. * After a fork() in a multithreaded program, the child can safely call only async-signal-safe
  52. functions (see signal-safety(7)) until such time as it calls execve(2).
  53. * The child inherits copies of the parent's set of open file descriptors. Each file descriptor
  54. in the child refers to the same open file description (see open(2)) as the corresponding file
  55. descriptor in the parent. This means that the two file descriptors share open file status
  56. flags, file offset, and signal-driven I/O attributes (see the description of F_SETOWN and
  57. F_SETSIG in fcntl(2)).
  58. * The child inherits copies of the parent's set of open message queue descriptors (see mq_over‐
  59. view(7)). Each file descriptor in the child refers to the same open message queue description
  60. as the corresponding file descriptor in the parent. This means that the two file descriptors
  61. share the same flags (mq_flags).
  62. * The child inherits copies of the parent's set of open directory streams (see opendir(3)).
  63. POSIX.1 says that the corresponding directory streams in the parent and child may share the
  64. directory stream positioning; on Linux/glibc they do not.
  65. RETURN VALUE
  66. On success, the PID of the child process is returned in the parent, and 0 is returned in the
  67. child. On failure, -1 is returned in the parent, no child process is created, and errno is set
  68. appropriately.
  69. ERRORS
  70. EAGAIN A system-imposed limit on the number of threads was encountered. There are a number of
  71. limits that may trigger this error:
  72. * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)), which limits the number of
  73. processes and threads for a real user ID, was reached;
  74. * the kernel's system-wide limit on the number of processes and threads, /proc/sys/ker‐
  75. nel/threads-max, was reached (see proc(5));
  76. * the maximum number of PIDs, /proc/sys/kernel/pid_max, was reached (see proc(5)); or
  77. * the PID limit (pids.max) imposed by the cgroup "process number" (PIDs) controller was
  78. reached.
  79. EAGAIN The caller is operating under the SCHED_DEADLINE scheduling policy and does not have the
  80. reset-on-fork flag set. See sched(7).
  81. ENOMEM fork() failed to allocate the necessary kernel structures because memory is tight.
  82. ENOMEM An attempt was made to create a child process in a PID namespace whose "init" process has
  83. terminated. See pid_namespaces(7).
  84. ENOSYS fork() is not supported on this platform (for example, hardware without a Memory-Manage‐
  85. ment Unit).
  86. ERESTARTNOINTR (since Linux 2.6.17)
  87. System call was interrupted by a signal and will be restarted. (This can be seen only
  88. during a trace.)
  89. CONFORMING TO
  90. POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.
  91. NOTES
  92. Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs
  93. is the time and memory required to duplicate the parent's page tables, and to create a unique
  94. task structure for the child.
  95. C library/kernel differences
  96. Since version 2.3.3, rather than invoking the kernel's fork() system call, the glibc fork() wrap‐
  97. per that is provided as part of the NPTL threading implementation invokes clone(2) with flags
  98. that provide the same effect as the traditional system call. (A call to fork() is equivalent to
  99. a call to clone(2) specifying flags as just SIGCHLD.) The glibc wrapper invokes any fork han‐
  100. dlers that have been established using pthread_atfork(3).
  101. EXAMPLES
  102. See pipe(2) and wait(2).
  103. SEE ALSO
  104. clone(2), execve(2), exit(2), setrlimit(2), unshare(2), vfork(2), wait(2), daemon(3), pthread_at‐
  105. fork(3), capabilities(7), credentials(7)
  106. COLOPHON
  107. This page is part of release 5.10 of the Linux man-pages project. A description of the project,
  108. information about reporting bugs, and the latest version of this page, can be found at
  109. https://www.kernel.org/doc/man-pages/.
  110. Linux 2020-06-09 FORK(2)

fork代码示例02.1

  1. #include<sys/types.h>
  2. #include<unistd.h>
  3. #include<stdio.h>
  4. int main(void)
  5. {
  6. pid_t pid;
  7. pid=fork();
  8. printf("pid=%d\n",pid);
  9. printf("hello world\n");
  10. return 0;
  11. }

 fork代码示例02.2

  1. #include<sys/types.h>
  2. #include<unistd.h>
  3. #include <stdio.h>
  4. int main(void)
  5. {
  6. pid_t pid1,pid2;
  7. pid1=fork();
  8. pid2=fork();
  9. printf("pid1=%d,pid2=%d\n",pid1,pid2);
  10. while(1);
  11. return 0;
  12. }

输出

:~/Desktop# ./a.out

pid1=24387B,pid2=24388C

pid1=24387B,pid2=0

pid1=0,pid2=24389D

pid1=0,pid2=0

分析程序执行的流程 

 加入循环 调出进程树 pstree -p

 

   可以分析进程id大概就是这样执行的  不过进程之间是独立的 不一定谁先执行,

03 进程并发

为什么用到多进程?
        希望父 子进程(独立分割)执行不同的内容

并发执行代码示例03.1

  1. #include<sys/types.h>
  2. #include<unistd.h>
  3. #include <stdio.h>
  4. int main(void)
  5. {
  6. pid_t pid;
  7. pid=fork();
  8. if(pid>0){ //父进程
  9. while(1){
  10. printf("hello world\n");
  11. sleep(1);
  12. }
  13. }
  14. else if(pid==0){
  15. while(1){
  16. printf("good moring\n");
  17. sleep(1);
  18. }
  19. }
  20. else{
  21. printf("err\n");
  22. }
  23. return 0;
  24. }

Hello world 和 good moring 并行执行

 不能根据输出结果 判断谁先执行

微观:默认情况下(内核) 父进程先调用
        父进程在创建 子进程的过程  正在执行中

父进程的结束 不会影响子进程的执行?

        状态影响

 状态影响代码示例03.2

  1. #include<sys/types.h>
  2. #include<unistd.h>
  3. #include <stdio.h>
  4. int main(void)
  5. {
  6. pid_t pid;
  7. int count = 0;
  8. pid=fork();
  9. if(pid>0){ //父进程
  10. for(int i=0;i<10;i++){
  11. printf("hello world count=%d\n",count++);
  12. sleep(1);}
  13. }
  14. else if(pid==0){
  15. while(1){
  16. printf("good moring count=%d\n",count++);
  17. sleep(1);
  18. }
  19. }
  20. else{
  21. printf("err\n");
  22. }
  23. return 0;
  24. }

输出

 可以看出父进程的结束 并没有影响的子进程的执行状态。

...........................................................................................................................................................

有没有手段!进程同步监控子进程的状态...

怎样才能影响!任务之间的通信和同步...

04 进程监控

父进程监控子进程状态的改变(结束;停止;)

man wait

  1. WAIT(1POSIX) POSIX Programmer's Manual WAIT(1POSIX)
  2. PROLOG
  3. This manual page is part of the POSIX Programmer's Manual. The Linux implementation of this
  4. interface may differ (consult the corresponding Linux manual page for details of Linux behav‐
  5. ior), or the interface may not be implemented on Linux.
  6. NAME
  7. wait — await process completion
  8. SYNOPSIS
  9. wait [pid...]
  10. DESCRIPTION
  11. When an asynchronous list (see Section 2.9.3.1, Examples) is started by the shell, the process
  12. ID of the last command in each element of the asynchronous list shall become known in the cur‐
  13. rent shell execution environment; see Section 2.12, Shell Execution Environment.
  14. If the wait utility is invoked with no operands, it shall wait until all process IDs known to
  15. the invoking shell have terminated and exit with a zero exit status.
  16. If one or more pid operands are specified that represent known process IDs, the wait utility
  17. shall wait until all of them have terminated. If one or more pid operands are specified that
  18. represent unknown process IDs, wait shall treat them as if they were known process IDs that
  19. exited with exit status 127. The exit status returned by the wait utility shall be the exit
  20. status of the process requested by the last pid operand.
  21. The known process IDs are applicable only for invocations of wait in the current shell execu‐
  22. tion environment.
  23. OPTIONS
  24. None.
  25. OPERANDS
  26. The following operand shall be supported:
  27. pid One of the following:
  28. 1. The unsigned decimal integer process ID of a command, for which the utility is
  29. to wait for the termination.
  30. 2. A job control job ID (see the Base Definitions volume of POSIX.12017, Section
  31. 3.204, Job Control Job ID) that identifies a background process group to be
  32. waited for. The job control job ID notation is applicable only for invocations
  33. of wait in the current shell execution environment; see Section 2.12, Shell Exe‐
  34. cution Environment. The exit status of wait shall be determined by the last
  35. command in the pipeline.
  36. Note: The job control job ID type of pid is only available on systems sup‐
  37. porting the User Portability Utilities option.
  38. STDIN
  39. Not used.
  40. INPUT FILES
  41. None.
  42. ENVIRONMENT VARIABLES
  43. The following environment variables shall affect the execution of wait:
  44. LANG Provide a default value for the internationalization variables that are unset or
  45. null. (See the Base Definitions volume of POSIX.12017, Section 8.2, International‐
  46. ization Variables for the precedence of internationalization variables used to de‐
  47. termine the values of locale categories.)
  48. LC_ALL If set to a non-empty string value, override the values of all the other interna‐
  49. tionalization variables.
  50. LC_CTYPE Determine the locale for the interpretation of sequences of bytes of text data as
  51. characters (for example, single-byte as opposed to multi-byte characters in argu‐
  52. ments).
  53. LC_MESSAGES
  54. Determine the locale that should be used to affect the format and contents of diag‐
  55. nostic messages written to standard error.
  56. NLSPATH Determine the location of message catalogs for the processing of LC_MESSAGES.
  57. ASYNCHRONOUS EVENTS
  58. Default.
  59. STDOUT
  60. Not used.
  61. STDERR
  62. The standard error shall be used only for diagnostic messages.
  63. OUTPUT FILES
  64. None.
  65. EXTENDED DESCRIPTION
  66. None.
  67. EXIT STATUS
  68. If one or more operands were specified, all of them have terminated or were not known by the
  69. invoking shell, and the status of the last operand specified is known, then the exit status of
  70. wait shall be the exit status information of the command indicated by the last operand speci‐
  71. fied. If the process terminated abnormally due to the receipt of a signal, the exit status
  72. shall be greater than 128 and shall be distinct from the exit status generated by other sig‐
  73. nals, but the exact value is unspecified. (See the kill -l option.) Otherwise, the wait util‐
  74. ity shall exit with one of the following values:
  75. 0 The wait utility was invoked with no operands and all process IDs known by the invok‐
  76. ing shell have terminated.
  77. 1126 The wait utility detected an error.
  78. 127 The command identified by the last pid operand specified is unknown.
  79. CONSEQUENCES OF ERRORS
  80. Default.
  81. The following sections are informative.
  82. APPLICATION USAGE
  83. On most implementations, wait is a shell built-in. If it is called in a subshell or separate
  84. utility execution environment, such as one of the following:
  85. (wait)
  86. nohup wait ...
  87. find . -exec wait ... \;
  88. it returns immediately because there are no known process IDs to wait for in those environ‐
  89. ments.
  90. Historical implementations of interactive shells have discarded the exit status of terminated
  91. background processes before each shell prompt. Therefore, the status of background processes
  92. was usually lost unless it terminated while wait was waiting for it. This could be a serious
  93. problem when a job that was expected to run for a long time actually terminated quickly with a
  94. syntax or initialization error because the exit status returned was usually zero if the re‐
  95. quested process ID was not found. This volume of POSIX.12017 requires the implementation to
  96. keep the status of terminated jobs available until the status is requested, so that scripts
  97. like:
  98. j1&
  99. p1=$!
  100. j2&
  101. wait $p1
  102. echo Job 1 exited with status $?
  103. wait $!
  104. echo Job 2 exited with status $?
  105. work without losing status on any of the jobs. The shell is allowed to discard the status of
  106. any process if it determines that the application cannot get the process ID for that process
  107. from the shell. It is also required to remember only {CHILD_MAX} number of processes in this
  108. way. Since the only way to get the process ID from the shell is by using the '!' shell param‐
  109. eter, the shell is allowed to discard the status of an asynchronous list if "$!" was not ref‐
  110. erenced before another asynchronous list was started. (This means that the shell only has to
  111. keep the status of the last asynchronous list started if the application did not reference
  112. "$!". If the implementation of the shell is smart enough to determine that a reference to
  113. "$!" was not saved anywhere that the application can retrieve it later, it can use this infor‐
  114. mation to trim the list of saved information. Note also that a successful call to wait with no
  115. operands discards the exit status of all asynchronous lists.)
  116. If the exit status of wait is greater than 128, there is no way for the application to know if
  117. the waited-for process exited with that value or was killed by a signal. Since most utilities
  118. exit with small values, there is seldom any ambiguity. Even in the ambiguous cases, most ap‐
  119. plications just need to know that the asynchronous job failed; it does not matter whether it
  120. detected an error and failed or was killed and did not complete its job normally.
  121. EXAMPLES
  122. Although the exact value used when a process is terminated by a signal is unspecified, if it
  123. is known that a signal terminated a process, a script can still reliably determine which sig‐
  124. nal by using kill as shown by the following script:
  125. sleep 1000&
  126. pid=$!
  127. kill -kill $pid
  128. wait $pid
  129. echo $pid was terminated by a SIG$(kill -l $?) signal.
  130. If the following sequence of commands is run in less than 31 seconds:
  131. sleep 257 | sleep 31 &
  132. jobs -l %%
  133. either of the following commands returns the exit status of the second sleep in the pipeline:
  134. wait <pid of sleep 31>
  135. wait %%
  136. RATIONALE
  137. The description of wait does not refer to the waitpid() function from the System Interfaces
  138. volume of POSIX.12017 because that would needlessly overspecify this interface. However, the
  139. wording means that wait is required to wait for an explicit process when it is given an argu‐
  140. ment so that the status information of other processes is not consumed. Historical implementa‐
  141. tions use the wait() function defined in the System Interfaces volume of POSIX.12017 until
  142. wait() returns the requested process ID or finds that the requested process does not exist.
  143. Because this means that a shell script could not reliably get the status of all background
  144. children if a second background job was ever started before the first job finished, it is rec‐
  145. ommended that the wait utility use a method such as the functionality provided by the wait‐
  146. pid() function.
  147. The ability to wait for multiple pid operands was adopted from the KornShell.
  148. This new functionality was added because it is needed to determine the exit status of any
  149. asynchronous list accurately. The only compatibility problem that this change creates is for a
  150. script like
  151. while sleep 60 do
  152. job& echo Job started $(date) as $! done
  153. which causes the shell to monitor all of the jobs started until the script terminates or runs
  154. out of memory. This would not be a problem if the loop did not reference "$!" or if the script
  155. would occasionally wait for jobs it started.
  156. FUTURE DIRECTIONS
  157. None.
  158. SEE ALSO
  159. Chapter 2, Shell Command Language, kill, sh
  160. The Base Definitions volume of POSIX.12017, Section 3.204, Job Control Job ID, Chapter 8, En‐
  161. vironment Variables
  162. The System Interfaces volume of POSIX.12017, wait()
  163. COPYRIGHT
  164. Portions of this text are reprinted and reproduced in electronic form from IEEE Std
  165. 1003.1-2017, Standard for Information Technology -- Portable Operating System Interface
  166. (POSIX), The Open Group Base Specifications Issue 7, 2018 Edition, Copyright (C) 2018 by the
  167. Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of
  168. any discrepancy between this version and the original IEEE and The Open Group Standard, the
  169. original IEEE and The Open Group Standard is the referee document. The original Standard can
  170. be obtained online at http://www.opengroup.org/unix/online.html .
  171. Any typographical or formatting errors that appear in this page are most likely to have been
  172. introduced during the conversion of the source files to man page format. To report such er‐
  173. rors, see https://www.kernel.org/doc/man-pages/reporting_bugs.html .
  174. IEEE/The Open Group 2017 WAIT(1POSIX)

 wait代码示例04.1  传入参数让子进程延时 全部子进程延时完毕后父进程结束

  1. #include <sys/types.h>
  2. #include <sys/wait.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. //run model: ./a.out 10 5 15 (three child process, after 10, 5, 15seconds, they are over)
  7. int main(int argc, char *argv[])
  8. {
  9. pid_t child_pid;
  10. int numDead;
  11. int i;
  12. for(i = 1; i < argc; i++)
  13. {
  14. switch(fork())
  15. {
  16. case -1:
  17. perror("fork()");
  18. exit(0);
  19. case 0:
  20. printf("Child %d started with PID = %d, sleeping %s seconds\n", i, getpid(), argv[i]);
  21. sleep(atoi(argv[i]));
  22. exit(0);
  23. default:
  24. break;
  25. }
  26. }
  27. numDead = 0;
  28. while(1)
  29. {
  30. child_pid = wait(NULL);
  31. if(child_pid == -1)
  32. {
  33. printf("No more children, Byebye!\n");
  34. exit(0);
  35. }
  36. numDead++;
  37. printf("wait() returned child PID : %d(numDead = %d)\n", child_pid, numDead);
  38. }
  39. }

输出 

05 创建线程函数

复习下 线程 进程的概念

进程:(动态的概念)(运行着的程序)
        创建销毁 耗费资源大
        进程间独立
        多个进程可以是一个程序
        由内核定义 抽象的实体  开辟一系列资源
        有id号

线程:
        由进程创建
        进程结束 线程也将结束
        线程从属于进程,一个进程可以有多个线程
        线程之间共享进程的资源
        某一个崩溃 其他会受到影响
        创建销毁 耗费资源小

线程创建函数pthread_create接收四个参数

int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start rourtine)(void),void *arg);
        pthread_t *thread 输出类型参数  
        const pthread_attr_t *attr 结构体指针 放置线程的属性
        void *(*start rourtine)(void)指针函数  返回指针 接收参数指针  实际上接就是 线程执行的内容
        void *arg 传递现线程的参数

函数执行成功 返回0  错误返回error number

查看手册man pthread_cread

  1. PTHREAD_CREATE(3) Linux Programmer's Manual PTHREAD_CREATE(3)
  2. NAME
  3. pthread_create - create a new thread
  4. SYNOPSIS
  5. #include <pthread.h>
  6. int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
  7. void *(*start_routine) (void *), void *arg);
  8. Compile and link with -pthread.
  9. DESCRIPTION
  10. The pthread_create() function starts a new thread in the calling process. The new thread starts
  11. execution by invoking start_routine(); arg is passed as the sole argument of start_routine().
  12. The new thread terminates in one of the following ways:
  13. * It calls pthread_exit(3), specifying an exit status value that is available to another thread in
  14. the same process that calls pthread_join(3).
  15. * It returns from start_routine(). This is equivalent to calling pthread_exit(3) with the value
  16. supplied in the return statement.
  17. * It is canceled (see pthread_cancel(3)).
  18. * Any of the threads in the process calls exit(3), or the main thread performs a return from
  19. main(). This causes the termination of all threads in the process.
  20. The attr argument points to a pthread_attr_t structure whose contents are used at thread creation
  21. time to determine attributes for the new thread; this structure is initialized using
  22. pthread_attr_init(3) and related functions. If attr is NULL, then the thread is created with de‐
  23. fault attributes.
  24. Before returning, a successful call to pthread_create() stores the ID of the new thread in the buf‐
  25. fer pointed to by thread; this identifier is used to refer to the thread in subsequent calls to
  26. other pthreads functions.
  27. The new thread inherits a copy of the creating thread's signal mask (pthread_sigmask(3)). The set
  28. of pending signals for the new thread is empty (sigpending(2)). The new thread does not inherit
  29. the creating thread's alternate signal stack (sigaltstack(2)).
  30. The new thread inherits the calling thread's floating-point environment (fenv(3)).
  31. The initial value of the new thread's CPU-time clock is 0 (see pthread_getcpuclockid(3)).
  32. Linux-specific details
  33. The new thread inherits copies of the calling thread's capability sets (see capabilities(7)) and
  34. CPU affinity mask (see sched_setaffinity(2)).
  35. RETURN VALUE
  36. On success, pthread_create() returns 0; on error, it returns an error number, and the contents of
  37. *thread are undefined.
  38. ERRORS
  39. EAGAIN Insufficient resources to create another thread.
  40. EAGAIN A system-imposed limit on the number of threads was encountered. There are a number of lim‐
  41. its that may trigger this error: the RLIMIT_NPROC soft resource limit (set via setr‐
  42. limit(2)), which limits the number of processes and threads for a real user ID, was reached;
  43. the kernel's system-wide limit on the number of processes and threads, /proc/sys/ker‐
  44. nel/threads-max, was reached (see proc(5)); or the maximum number of PIDs, /proc/sys/ker‐
  45. nel/pid_max, was reached (see proc(5)).
  46. EINVAL Invalid settings in attr.
  47. EPERM No permission to set the scheduling policy and parameters specified in attr.
  48. ATTRIBUTES
  49. For an explanation of the terms used in this section, see attributes(7).
  50. ┌─────────────────┬───────────────┬─────────┐
  51. │Interface │ Attribute │ Value │
  52. ├─────────────────┼───────────────┼─────────┤
  53. pthread_create() │ Thread safety │ MT-Safe │
  54. └─────────────────┴───────────────┴─────────┘
  55. CONFORMING TO
  56. POSIX.1-2001, POSIX.1-2008.
  57. NOTES
  58. See pthread_self(3) for further information on the thread ID returned in *thread by pthread_cre‐
  59. ate(). Unless real-time scheduling policies are being employed, after a call to pthread_create(),
  60. it is indeterminate which thread—the caller or the new thread—will next execute.
  61. A thread may either be joinable or detached. If a thread is joinable, then another thread can call
  62. pthread_join(3) to wait for the thread to terminate and fetch its exit status. Only when a termi‐
  63. nated joinable thread has been joined are the last of its resources released back to the system.
  64. When a detached thread terminates, its resources are automatically released back to the system: it
  65. is not possible to join with the thread in order to obtain its exit status. Making a thread de‐
  66. tached is useful for some types of daemon threads whose exit status the application does not need
  67. to care about. By default, a new thread is created in a joinable state, unless attr was set to
  68. create the thread in a detached state (using pthread_attr_setdetachstate(3)).
  69. Under the NPTL threading implementation, if the RLIMIT_STACK soft resource limit at the time the
  70. program started has any value other than "unlimited", then it determines the default stack size of
  71. new threads. Using pthread_attr_setstacksize(3), the stack size attribute can be explicitly set in
  72. the attr argument used to create a thread, in order to obtain a stack size other than the default.
  73. If the RLIMIT_STACK resource limit is set to "unlimited", a per-architecture value is used for the
  74. stack size. Here is the value for a few architectures:
  75. ┌─────────────┬────────────────────┐
  76. │Architecture │ Default stack size │
  77. ├─────────────┼────────────────────┤
  78. │i386 │ 2 MB │
  79. ├─────────────┼────────────────────┤
  80. │IA-6432 MB │
  81. ├─────────────┼────────────────────┤
  82. │PowerPC │ 4 MB │
  83. ├─────────────┼────────────────────┤
  84. │S/3902 MB │
  85. ├─────────────┼────────────────────┤
  86. │Sparc-322 MB │
  87. ├─────────────┼────────────────────┤
  88. │Sparc-644 MB │
  89. ├─────────────┼────────────────────┤
  90. │x86_64 │ 2 MB │
  91. └─────────────┴────────────────────┘
  92. BUGS
  93. In the obsolete LinuxThreads implementation, each of the threads in a process has a different
  94. process ID. This is in violation of the POSIX threads specification, and is the source of many
  95. other nonconformances to the standard; see pthreads(7).
  96. EXAMPLES
  97. The program below demonstrates the use of pthread_create(), as well as a number of other functions
  98. in the pthreads API.
  99. In the following run, on a system providing the NPTL threading implementation, the stack size de‐
  100. faults to the value given by the "stack size" resource limit:
  101. $ ulimit -s
  102. 8192 # The stack size limit is 8 MB (0x800000 bytes)
  103. $ ./a.out hola salut servus
  104. Thread 1: top of stack near 0xb7dd03b8; argv_string=hola
  105. Thread 2: top of stack near 0xb75cf3b8; argv_string=salut
  106. Thread 3: top of stack near 0xb6dce3b8; argv_string=servus
  107. Joined with thread 1; returned value was HOLA
  108. Joined with thread 2; returned value was SALUT
  109. Joined with thread 3; returned value was SERVUS
  110. In the next run, the program explicitly sets a stack size of 1 MB (using pthread_attr_setstack‐
  111. size(3)) for the created threads:
  112. $ ./a.out -s 0x100000 hola salut servus
  113. Thread 1: top of stack near 0xb7d723b8; argv_string=hola
  114. Thread 2: top of stack near 0xb7c713b8; argv_string=salut
  115. Thread 3: top of stack near 0xb7b703b8; argv_string=servus
  116. Joined with thread 1; returned value was HOLA
  117. Joined with thread 2; returned value was SALUT
  118. Joined with thread 3; returned value was SERVUS
  119. Program source
  120. #include <pthread.h>
  121. #include <string.h>
  122. #include <stdio.h>
  123. #include <stdlib.h>
  124. #include <unistd.h>
  125. #include <errno.h>
  126. #include <ctype.h>
  127. #define handle_error_en(en, msg) \
  128. do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
  129. #define handle_error(msg) \
  130. do { perror(msg); exit(EXIT_FAILURE); } while (0)
  131. struct thread_info { /* Used as argument to thread_start() */
  132. pthread_t thread_id; /* ID returned by pthread_create() */
  133. int thread_num; /* Application-defined thread # */
  134. char *argv_string; /* From command-line argument */
  135. };
  136. /* Thread start function: display address near top of our stack,
  137. and return upper-cased copy of argv_string */
  138. static void *
  139. thread_start(void *arg)
  140. {
  141. struct thread_info *tinfo = arg;
  142. char *uargv;
  143. printf("Thread %d: top of stack near %p; argv_string=%s\n",
  144. tinfo->thread_num, &p, tinfo->argv_string);
  145. uargv = strdup(tinfo->argv_string);
  146. if (uargv == NULL)
  147. handle_error("strdup");
  148. for (char *p = uargv; *p != '\0'; p++)
  149. *p = toupper(*p);
  150. return uargv;
  151. }
  152. int
  153. main(int argc, char *argv[])
  154. {
  155. int s, opt, num_threads;
  156. pthread_attr_t attr;
  157. size_t stack_size;
  158. void *res;
  159. /* The "-s" option specifies a stack size for our threads */
  160. stack_size = -1;
  161. while ((opt = getopt(argc, argv, "s:")) != -1) {
  162. switch (opt) {
  163. case 's':
  164. stack_size = strtoul(optarg, NULL, 0);
  165. break;
  166. default:
  167. fprintf(stderr, "Usage: %s [-s stack-size] arg...\n",
  168. argv[0]);
  169. exit(EXIT_FAILURE);
  170. }
  171. }
  172. num_threads = argc - optind;
  173. /* Initialize thread creation attributes */
  174. s = pthread_attr_init(&attr);
  175. if (s != 0)
  176. handle_error_en(s, "pthread_attr_init");
  177. if (stack_size > 0) {
  178. s = pthread_attr_setstacksize(&attr, stack_size);
  179. if (s != 0)
  180. handle_error_en(s, "pthread_attr_setstacksize");
  181. }
  182. /* Allocate memory for pthread_create() arguments */
  183. struct thread_info *tinfo = calloc(num_threads, sizeof(*tinfo));
  184. if (tinfo == NULL)
  185. handle_error("calloc");
  186. /* Create one thread for each command-line argument */
  187. for (int tnum = 0; tnum < num_threads; tnum++) {
  188. tinfo[tnum].thread_num = tnum + 1;
  189. tinfo[tnum].argv_string = argv[optind + tnum];
  190. /* The pthread_create() call stores the thread ID into
  191. corresponding element of tinfo[] */
  192. s = pthread_create(&tinfo[tnum].thread_id, &attr,
  193. &thread_start, &tinfo[tnum]);
  194. if (s != 0)
  195. handle_error_en(s, "pthread_create");
  196. }
  197. /* Destroy the thread attributes object, since it is no
  198. longer needed */
  199. s = pthread_attr_destroy(&attr);
  200. if (s != 0)
  201. handle_error_en(s, "pthread_attr_destroy");
  202. /* Now join with each thread, and display its returned value */
  203. for (int tnum = 0; tnum < num_threads; tnum++) {
  204. s = pthread_join(tinfo[tnum].thread_id, &res);
  205. if (s != 0)
  206. handle_error_en(s, "pthread_join");
  207. printf("Joined with thread %d; returned value was %s\n",
  208. tinfo[tnum].thread_num, (char *) res);
  209. free(res); /* Free memory allocated by thread */
  210. }
  211. free(tinfo);
  212. exit(EXIT_SUCCESS);
  213. }
  214. SEE ALSO
  215. getrlimit(2), pthread_attr_init(3), pthread_cancel(3), pthread_detach(3), pthread_equal(3),
  216. pthread_exit(3), pthread_getattr_np(3), pthread_join(3), pthread_self(3),
  217. pthread_setattr_default_np(3), pthreads(7)
  218. COLOPHON
  219. This page is part of release 5.10 of the Linux man-pages project. A description of the project,
  220. information about reporting bugs, and the latest version of this page, can be found at
  221. https://www.kernel.org/doc/man-pages/.
  222. Linux 2020-11-01 PTHREAD_CREATE(3)

进程等待线程函数 pthread_join

man pthread_join

  1. PTHREAD_JOIN(3) Linux Programmer's Manual PTHREAD_JOIN(3)
  2. NAME
  3. pthread_join - join with a terminated thread
  4. SYNOPSIS
  5. #include <pthread.h>
  6. int pthread_join(pthread_t thread, void **retval);
  7. Compile and link with -pthread.
  8. DESCRIPTION
  9. The pthread_join() function waits for the thread specified by thread to terminate. If that thread has already
  10. terminated, then pthread_join() returns immediately. The thread specified by thread must be joinable.
  11. If retval is not NULL, then pthread_join() copies the exit status of the target thread (i.e., the value that
  12. the target thread supplied to pthread_exit(3)) into the location pointed to by retval. If the target thread
  13. was canceled, then PTHREAD_CANCELED is placed in the location pointed to by retval.
  14. If multiple threads simultaneously try to join with the same thread, the results are undefined. If the thread
  15. calling pthread_join() is canceled, then the target thread will remain joinable (i.e., it will not be de‐
  16. tached).
  17. RETURN VALUE
  18. On success, pthread_join() returns 0; on error, it returns an error number.
  19. ERRORS
  20. EDEADLK
  21. A deadlock was detected (e.g., two threads tried to join with each other); or thread specifies the call‐
  22. ing thread.
  23. EINVAL thread is not a joinable thread.
  24. EINVAL Another thread is already waiting to join with this thread.
  25. ESRCH No thread with the ID thread could be found.
  26. ATTRIBUTES
  27. For an explanation of the terms used in this section, see attributes(7).
  28. ┌───────────────┬───────────────┬─────────┐
  29. │Interface │ Attribute │ Value │
  30. ├───────────────┼───────────────┼─────────┤
  31. pthread_join() │ Thread safety │ MT-Safe │
  32. └───────────────┴───────────────┴─────────┘
  33. CONFORMING TO
  34. POSIX.1-2001, POSIX.1-2008.
  35. NOTES
  36. After a successful call to pthread_join(), the caller is guaranteed that the target thread has terminated. The
  37. caller may then choose to do any clean-up that is required after termination of the thread (e.g., freeing mem‐
  38. ory or other resources that were allocated to the target thread).
  39. Joining with a thread that has previously been joined results in undefined behavior.
  40. Failure to join with a thread that is joinable (i.e., one that is not detached), produces a "zombie thread".
  41. Avoid doing this, since each zombie thread consumes some system resources, and when enough zombie threads have
  42. accumulated, it will no longer be possible to create new threads (or processes).
  43. There is no pthreads analog of waitpid(-1, &status, 0), that is, "join with any terminated thread". If you be‐
  44. lieve you need this functionality, you probably need to rethink your application design.
  45. All of the threads in a process are peers: any thread can join with any other thread in the process.
  46. EXAMPLES
  47. See pthread_create(3).
  48. SEE ALSO
  49. pthread_cancel(3), pthread_create(3), pthread_detach(3), pthread_exit(3), pthread_tryjoin_np(3), pthreads(7)
  50. COLOPHON
  51. This page is part of release 5.10 of the Linux man-pages project. A description of the project, information
  52. about reporting bugs, and the latest version of this page, can be found at
  53. https://www.kernel.org/doc/man-pages/.
  54. Linux 2020-06-09 PTHREAD_JOIN(3)

创建线程代码示例05.1

  1. #include <pthread.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. void *thread_function(void *arg);
  6. int main(void)
  7. {
  8. pthread_t pthread;
  9. int ret;
  10. int count = 8;
  11. ret = pthread_create(&pthread, NULL, thread_function, &count);
  12. if(ret != 0)
  13. {
  14. perror("pthread_create");
  15. exit(1);
  16. }
  17. pthread_join(pthread, NULL);
  18. printf("The thread is over, process is over too.\n");
  19. return 0;
  20. }
  21. void *thread_function(void *arg)
  22. {
  23. int i;
  24. printf("Thread begins running\n");
  25. for(i = 0; i < *(int *)arg; i++)
  26. {
  27. printf("Hello world\n");
  28. sleep(1);
  29. }
  30. return NULL;
  31. }

 

06 多线程以及线程间的共享

创建多线程的方法与创建一个线程的方法是一样的

代码示例 06.1

  1. #include <pthread.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. void *thread1_function(void *arg);
  6. void *thread2_function(void *arg);
  7. int count = 0;//线程可见
  8. int main(void)
  9. {
  10. pthread_t pthread1, pthread2;
  11. int ret;
  12. ret = pthread_create(&pthread1, NULL, thread1_function, NULL);
  13. if(ret != 0)
  14. {
  15. perror("pthread_create");
  16. exit(1);
  17. }
  18. ret = pthread_create(&pthread2, NULL, thread2_function, NULL);
  19. if(ret != 0)
  20. {
  21. perror("pthread_create");
  22. exit(1);
  23. }
  24. pthread_join(pthread1, NULL);
  25. pthread_join(pthread2, NULL);
  26. printf("The thread is over, process is over too.\n");
  27. return 0;
  28. }
  29. void *thread1_function(void *arg)
  30. {
  31. printf("Thread1 begins running\n");
  32. while(1)
  33. {
  34. printf("Thread1 count = %d\n", count++);
  35. sleep(1);
  36. }
  37. return NULL;
  38. }
  39. void *thread2_function(void *arg)
  40. {
  41. printf("Thread2 begins running\n");
  42. while(1)
  43. {
  44. printf("Thread2 count = %d\n", count++);
  45. sleep(1);
  46. }
  47. return NULL;
  48. }

 

07 进程通信——无名管道

进程间的通信收手段

管道 pipe
        命名管道
        无名管道  单向

man pipe

  1. PIPE(2) Linux Programmer's Manual PIPE(2)
  2. NAME
  3. pipe, pipe2 - create pipe
  4. SYNOPSIS
  5. #include <unistd.h>
  6. /* On Alpha, IA-64, MIPS, SuperH, and SPARC/SPARC64; see NOTES */
  7. struct fd_pair {
  8. long fd[2];
  9. };
  10. struct fd_pair pipe();
  11. /* On all other architectures */
  12. int pipe(int pipefd[2]);
  13. #define _GNU_SOURCE /* See feature_test_macros(7) */
  14. #include <fcntl.h> /* Obtain O_* constant definitions */
  15. #include <unistd.h>
  16. int pipe2(int pipefd[2], int flags);
  17. DESCRIPTION
  18. pipe() creates a pipe, a unidirectional data channel that can be used for interprocess communication. The ar‐
  19. ray pipefd is used to return two file descriptors referring to the ends of the pipe. pipefd[0] refers to the
  20. read end of the pipe. pipefd[1] refers to the write end of the pipe. Data written to the write end of the
  21. pipe is buffered by the kernel until it is read from the read end of the pipe. For further details, see
  22. pipe(7).
  23. If flags is 0, then pipe2() is the same as pipe(). The following values can be bitwise ORed in flags to obtain
  24. different behavior:
  25. O_CLOEXEC
  26. Set the close-on-exec (FD_CLOEXEC) flag on the two new file descriptors. See the description of the
  27. same flag in open(2) for reasons why this may be useful.
  28. O_DIRECT (since Linux 3.4)
  29. Create a pipe that performs I/O in "packet" mode. Each write(2) to the pipe is dealt with as a separate
  30. packet, and read(2)s from the pipe will read one packet at a time. Note the following points:
  31. * Writes of greater than PIPE_BUF bytes (see pipe(7)) will be split into multiple packets. The con‐
  32. stant PIPE_BUF is defined in <limits.h>.
  33. * If a read(2) specifies a buffer size that is smaller than the next packet, then the requested number
  34. of bytes are read, and the excess bytes in the packet are discarded. Specifying a buffer size of
  35. PIPE_BUF will be sufficient to read the largest possible packets (see the previous point).
  36. * Zero-length packets are not supported. (A read(2) that specifies a buffer size of zero is a no-op,
  37. and returns 0.)
  38. Older kernels that do not support this flag will indicate this via an EINVAL error.
  39. Since Linux 4.5, it is possible to change the O_DIRECT setting of a pipe file descriptor using fcntl(2).
  40. O_NONBLOCK
  41. Set the O_NONBLOCK file status flag on the open file descriptions referred to by the new file descrip‐
  42. tors. Using this flag saves extra calls to fcntl(2) to achieve the same result.
  43. RETURN VALUE
  44. On success, zero is returned. On error, -1 is returned, errno is set appropriately, and pipefd is left un‐
  45. changed.
  46. On Linux (and other systems), pipe() does not modify pipefd on failure. A requirement standardizing this be‐
  47. havior was added in POSIX.1-2008 TC2. The Linux-specific pipe2() system call likewise does not modify pipefd
  48. on failure.
  49. ERRORS
  50. EFAULT pipefd is not valid.
  51. EINVAL (pipe2()) Invalid value in flags.
  52. EMFILE The per-process limit on the number of open file descriptors has been reached.
  53. ENFILE The system-wide limit on the total number of open files has been reached.
  54. ENFILE The user hard limit on memory that can be allocated for pipes has been reached and the caller is not
  55. privileged; see pipe(7).
  56. VERSIONS
  57. pipe2() was added to Linux in version 2.6.27; glibc support is available starting with version 2.9.
  58. CONFORMING TO
  59. pipe(): POSIX.1-2001, POSIX.1-2008.
  60. pipe2() is Linux-specific.
  61. NOTES
  62. The System V ABI on some architectures allows the use of more than one register for returning multiple values;
  63. several architectures (namely, Alpha, IA-64, MIPS, SuperH, and SPARC/SPARC64) (ab)use this feature in order to
  64. implement the pipe() system call in a functional manner: the call doesn't take any arguments and returns a pair
  65. of file descriptors as the return value on success. The glibc pipe() wrapper function transparently deals with
  66. this. See syscall(2) for information regarding registers used for storing second file descriptor.
  67. EXAMPLES
  68. The following program creates a pipe, and then fork(2)s to create a child process; the child inherits a dupli‐
  69. cate set of file descriptors that refer to the same pipe. After the fork(2), each process closes the file de‐
  70. scriptors that it doesn't need for the pipe (see pipe(7)). The parent then writes the string contained in the
  71. program's command-line argument to the pipe, and the child reads this string a byte at a time from the pipe and
  72. echoes it on standard output.
  73. Program source
  74. #include <sys/types.h>
  75. #include <sys/wait.h>
  76. #include <stdio.h>
  77. #include <stdlib.h>
  78. #include <unistd.h>
  79. #include <string.h>
  80. int
  81. main(int argc, char *argv[])
  82. {
  83. int pipefd[2];
  84. pid_t cpid;
  85. char buf;
  86. if (argc != 2) {
  87. fprintf(stderr, "Usage: %s <string>\n", argv[0]);
  88. exit(EXIT_FAILURE);
  89. }
  90. if (pipe(pipefd) == -1) {
  91. perror("pipe");
  92. exit(EXIT_FAILURE);
  93. }
  94. cpid = fork();
  95. if (cpid == -1) {
  96. perror("fork");
  97. exit(EXIT_FAILURE);
  98. }
  99. if (cpid == 0) { /* Child reads from pipe */
  100. close(pipefd[1]); /* Close unused write end */
  101. while (read(pipefd[0], &buf, 1) > 0)
  102. write(STDOUT_FILENO, &buf, 1);
  103. write(STDOUT_FILENO, "\n", 1);
  104. close(pipefd[0]);
  105. _exit(EXIT_SUCCESS);
  106. } else { /* Parent writes argv[1] to pipe */
  107. close(pipefd[0]); /* Close unused read end */
  108. write(pipefd[1], argv[1], strlen(argv[1]));
  109. close(pipefd[1]); /* Reader will see EOF */
  110. wait(NULL); /* Wait for child */
  111. exit(EXIT_SUCCESS);
  112. }
  113. }
  114. SEE ALSO
  115. fork(2), read(2), socketpair(2), splice(2), tee(2), vmsplice(2), write(2), popen(3), pipe(7)
  116. COLOPHON
  117. This page is part of release 5.10 of the Linux man-pages project. A description of the project, information
  118. about reporting bugs, and the latest version of this page, can be found at
  119. https://www.kernel.org/doc/man-pages/.
  120. Linux 2020-06-09 PIPE(2)

现实现 利用管道 父进程向子进程写入数据。

代码示例07.1

  1. /*
  2. parent process: write pipe
  3. child process: read pipe
  4. */
  5. #include <unistd.h>
  6. #include <sys/types.h>
  7. #include <stdio.h>
  8. int main(void)
  9. {
  10. int fd[2];
  11. int pid;
  12. if(pipe(fd) == -1)
  13. perror("pipe");
  14. pid = fork();
  15. if(pid > 0) //parent process
  16. {
  17. close(fd[0]);
  18. sleep(5);
  19. write(fd[1], "ab", 2);
  20. while(1);
  21. }
  22. else if(pid == 0)
  23. {
  24. char ch[2];
  25. printf("Child process is waiting for data: \n");
  26. close(fd[1]);
  27. read(fd[0], ch, 2);//没有写入 阻塞等待
  28. printf("Read from pipe: %s\n", ch);
  29. }
  30. return 0;
  31. }

08 测量无名管道的大小

向管道循环注入数据测试管道能够装载的最大值

代码示例08.1.c

  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. #include <stdio.h>
  4. #include <sys/wait.h>
  5. int main(void)
  6. {
  7. pid_t pid;
  8. int fd[2];
  9. if(pipe(fd) == -1)
  10. perror("pipe");
  11. pid = fork();
  12. if(pid == 0) //child process: write to the pipe
  13. {
  14. char ch = '*';
  15. int n = 0;
  16. close(fd[0]);
  17. while(1)
  18. {
  19. write(fd[1], &ch, 1);
  20. printf("count = %d\n", ++n);
  21. }
  22. }
  23. else if(pid > 0) //parent process: wait until child process is over
  24. {
  25. waitpid(pid, NULL, 0);
  26. }
  27. }

09 无名管道进程通信实例

父进程等待之进程的输入。

代码示例09.1.c

  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. #include <stdio.h>
  4. #include <sys/wait.h>
  5. int main(void)
  6. {
  7. pid_t pid;
  8. int fd[2];
  9. if(pipe(fd) == -1)
  10. perror("pipe");
  11. pid = fork();
  12. if(pid == 0)
  13. {
  14. char tmp[100];
  15. close(fd[0]);
  16. while(1)
  17. {
  18. scanf("%s", tmp);
  19. write(fd[1], tmp, sizeof(tmp));
  20. }
  21. }
  22. else if(pid > 0)
  23. {
  24. char tmp[100];
  25. close(fd[1]);
  26. while(1)
  27. {
  28. printf("Parent process is waiting for the data from pipe:\n");
  29. read(fd[0], tmp, sizeof(tmp));
  30. printf("read from pipe: %s\n", tmp);
  31. }
  32. }
  33. return 0;
  34. }

10 管道双向传输

父进程实现小写转换大写传回子进程输出。

代码示例10.1.c

  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. #include <stdio.h>
  4. #include <sys/wait.h>
  5. #include <string.h>
  6. #include <ctype.h>
  7. int main(void)
  8. {
  9. pid_t pid;
  10. int fd[2];
  11. int fd2[2];
  12. if(pipe(fd) == -1)
  13. perror("pipe");
  14. if(pipe(fd2) == -1)
  15. perror("pipe");
  16. pid = fork();
  17. if(pid == 0)
  18. {
  19. char tmp[100];
  20. int i;
  21. close(fd[1]);
  22. close(fd2[0]);
  23. while(1)
  24. {
  25. memset(tmp, '\0', sizeof(tmp));
  26. read(fd[0], tmp, sizeof(tmp));
  27. for(i = 0; i < sizeof(tmp); i++)
  28. tmp[i] = toupper(tmp[i]);
  29. write(fd2[1], tmp, sizeof(tmp));
  30. }
  31. }
  32. else if(pid > 0)
  33. {
  34. char tmp[100];
  35. close(fd[0]);
  36. close(fd2[1]);
  37. while(1)
  38. {
  39. memset(tmp, '\0', sizeof(tmp));
  40. gets(tmp);
  41. write(fd[1], tmp, sizeof(tmp));
  42. memset(tmp, '\0', sizeof(tmp));
  43. read(fd2[0], tmp, sizeof(tmp));
  44. printf("After change: %s\n", tmp);
  45. }
  46. }
  47. return 0;
  48. }

11 有名管道

概念引出
        无名管道只适用于有亲缘关系的进程间。
        没有亲缘关系的两个进程是否可以进行通信 ?

查看liunx编程手册
        通过man man 得知 序号3是库调用 1是shell命名 2是系统调用
        man 3 mkfifo

       1   Executable programs or shell commands
       2   System calls (functions provided by the kernel)
       3   Library calls (functions within program libraries)
       4   Special files (usually found in /dev)
       5   File formats and conventions, e.g. /etc/passwd
       6   Games
       7   Miscellaneous  (including  macro  packages and conventions), e.g.
           man(7), groff(7), man-pages(7)
       8   System administration commands (usually only for root)
       9   Kernel routines [Non standard]
  1. MKFIFO(3) Linux Programmer's Manual MKFIFO(3)
  2. NAME
  3. mkfifo, mkfifoat - make a FIFO special file (a named pipe)
  4. SYNOPSIS
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. int mkfifo(const char *pathname, mode_t mode);
  8. #include <fcntl.h> /* Definition of AT_* constants */
  9. #include <sys/stat.h>
  10. int mkfifoat(int dirfd, const char *pathname, mode_t mode);
  11. Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
  12. mkfifoat():
  13. Since glibc 2.10:
  14. _POSIX_C_SOURCE >= 200809L
  15. Before glibc 2.10:
  16. _ATFILE_SOURCE
  17. DESCRIPTION
  18. mkfifo() makes a FIFO special file with name pathname. mode specifies the
  19. FIFO's permissions. It is modified by the process's umask in the usual
  20. way: the permissions of the created file are (mode & ~umask).
  21. A FIFO special file is similar to a pipe, except that it is created in a
  22. different way. Instead of being an anonymous communications channel, a
  23. FIFO special file is entered into the filesystem by calling mkfifo().
  24. Once you have created a FIFO special file in this way, any process can
  25. open it for reading or writing, in the same way as an ordinary file. How‐
  26. ever, it has to be open at both ends simultaneously before you can proceed
  27. to do any input or output operations on it. Opening a FIFO for reading
  28. normally blocks until some other process opens the same FIFO for writing,
  29. and vice versa. See fifo(7) for nonblocking handling of FIFO special
  30. files.
  31. mkfifoat()
  32. The mkfifoat() function operates in exactly the same way as mkfifo(), ex‐
  33. cept for the differences described here.
  34. If the pathname given in pathname is relative, then it is interpreted rel‐
  35. ative to the directory referred to by the file descriptor dirfd (rather
  36. than relative to the current working directory of the calling process, as
  37. is done by mkfifo() for a relative pathname).
  38. If pathname is relative and dirfd is the special value AT_FDCWD, then
  39. pathname is interpreted relative to the current working directory of the
  40. calling process (like mkfifo()).
  41. If pathname is absolute, then dirfd is ignored.
  42. RETURN VALUE
  43. On success mkfifo() and mkfifoat() return 0. In the case of an error, -1
  44. is returned (in which case, errno is set appropriately).
  45. ERRORS
  46. EACCES One of the directories in pathname did not allow search (execute)
  47. permission.
  48. EDQUOT The user's quota of disk blocks or inodes on the filesystem has
  49. been exhausted.
  50. EEXIST pathname already exists. This includes the case where pathname is
  51. a symbolic link, dangling or not.
  52. ENAMETOOLONG
  53. Either the total length of pathname is greater than PATH_MAX, or an
  54. individual filename component has a length greater than NAME_MAX.
  55. In the GNU system, there is no imposed limit on overall filename
  56. length, but some filesystems may place limits on the length of a
  57. component.
  58. ENOENT A directory component in pathname does not exist or is a dangling
  59. symbolic link.
  60. ENOSPC The directory or filesystem has no room for the new file.
  61. ENOTDIR
  62. A component used as a directory in pathname is not, in fact, a di‐
  63. rectory.
  64. EROFS pathname refers to a read-only filesystem.
  65. The following additional errors can occur for mkfifoat():
  66. EBADF dirfd is not a valid file descriptor.
  67. ENOTDIR
  68. pathname is a relative path and dirfd is a file descriptor refer‐
  69. ring to a file other than a directory.
  70. VERSIONS
  71. mkfifoat() was added to glibc in version 2.4. It is implemented using
  72. mknodat(2), available on Linux since kernel 2.6.16.
  73. ATTRIBUTES
  74. For an explanation of the terms used in this section, see attributes(7).
  75. ┌─────────────────────┬───────────────┬─────────┐
  76. │Interface │ Attribute │ Value │
  77. ├─────────────────────┼───────────────┼─────────┤
  78. │mkfifo(), mkfifoat() │ Thread safety │ MT-Safe │
  79. └─────────────────────┴───────────────┴─────────┘
  80. CONFORMING TO
  81. mkfifo(): POSIX.1-2001, POSIX.1-2008.
  82. mkfifoat(): POSIX.1-2008.
  83. SEE ALSO
  84. mkfifo(1), close(2), open(2), read(2), stat(2), umask(2), write(2),
  85. fifo(7)
  86. COLOPHON
  87. This page is part of release 5.10 of the Linux man-pages project. A de‐
  88. scription of the project, information about reporting bugs, and the latest
  89. version of this page, can be found at
  90. https://www.kernel.org/doc/man-pages/.
  91. GNU 2020-08-13 MKFIFO(3)

代码示例11.1.c 创建有名管道 一直向管道读取

  1. #include <stdio.h>
  2. #include <sys/stat.h>
  3. #include <sys/types.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <string.h>
  7. int main(void)
  8. {
  9. int ret;
  10. int fd;
  11. char buf[100];
  12. ret = mkfifo("my_fifo", 0666);
  13. if(ret != 0)
  14. perror("mkfifo");
  15. printf("Prepare reading from named pipe:\n");
  16. fd = open("my_fifo", O_RDWR);
  17. if(fd == -1)
  18. perror("open");
  19. while(1)
  20. {
  21. memset(buf, '\0', sizeof(buf));
  22. read(fd, buf, sizeof(buf));
  23. printf("Read from named pipe: %s\n", buf);
  24. sleep(1);
  25. }
  26. return 0;
  27. }

代码示例11.2.c 用户交互 向管道写入数据

  1. #include <stdio.h>
  2. #include <sys/stat.h>
  3. #include <sys/types.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <string.h>
  7. #include <stdlib.h>
  8. int main(int argc, char *argv[])
  9. {
  10. int fd;
  11. char buf[100];
  12. fd = open("my_fifo", O_WRONLY);
  13. if(fd == -1)
  14. perror("open");
  15. if(argc == 1)
  16. {
  17. printf("Please send something to the named pipe:\n");
  18. exit(EXIT_FAILURE);
  19. }
  20. strcpy(buf, argv[1]);
  21. write(fd, buf, sizeof(buf));
  22. printf("Write to the pipe: %s\n", buf);
  23. return 0;
  24. }

 

12 共享内存

man shmget

  1. SHMGET(2) Linux Programmer's Manual SHMGET(2)
  2. NAME
  3. shmget - allocates a System V shared memory segment
  4. SYNOPSIS
  5. #include <sys/ipc.h>
  6. #include <sys/shm.h>
  7. int shmget(key_t key, size_t size, int shmflg);
  8. DESCRIPTION
  9. shmget() returns the identifier of the System V shared memory segment associated with the value of the argument key. It may be used ei‐
  10. ther to obtain the identifier of a previously created shared memory segment (when shmflg is zero and key does not have the value IPC_PRI‐
  11. VATE), or to create a new set.
  12. A new shared memory segment, with size equal to the value of size rounded up to a multiple of PAGE_SIZE, is created if key has the value
  13. IPC_PRIVATE or key isn't IPC_PRIVATE, no shared memory segment corresponding to key exists, and IPC_CREAT is specified in shmflg.
  14. If shmflg specifies both IPC_CREAT and IPC_EXCL and a shared memory segment already exists for key, then shmget() fails with errno set to
  15. EEXIST. (This is analogous to the effect of the combination O_CREAT | O_EXCL for open(2).)
  16. The value shmflg is composed of:
  17. IPC_CREAT
  18. Create a new segment. If this flag is not used, then shmget() will find the segment associated with key and check to see if the
  19. user has permission to access the segment.
  20. IPC_EXCL
  21. This flag is used with IPC_CREAT to ensure that this call creates the segment. If the segment already exists, the call fails.
  22. SHM_HUGETLB (since Linux 2.6)
  23. Allocate the segment using "huge pages." See the Linux kernel source file Documentation/admin-guide/mm/hugetlbpage.rst for fur‐
  24. ther information.
  25. SHM_HUGE_2MB, SHM_HUGE_1GB (since Linux 3.8)
  26. Used in conjunction with SHM_HUGETLB to select alternative hugetlb page sizes (respectively, 2 MB and 1 GB) on systems that sup‐
  27. port multiple hugetlb page sizes.
  28. More generally, the desired huge page size can be configured by encoding the base-2 logarithm of the desired page size in the six
  29. bits at the offset SHM_HUGE_SHIFT. Thus, the above two constants are defined as:
  30. #define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT)
  31. #define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT)
  32. For some additional details, see the discussion of the similarly named constants in mmap(2).
  33. SHM_NORESERVE (since Linux 2.6.15)
  34. This flag serves the same purpose as the mmap(2) MAP_NORESERVE flag. Do not reserve swap space for this segment. When swap space
  35. is reserved, one has the guarantee that it is possible to modify the segment. When swap space is not reserved one might get
  36. SIGSEGV upon a write if no physical memory is available. See also the discussion of the file /proc/sys/vm/overcommit_memory in
  37. proc(5).
  38. In addition to the above flags, the least significant 9 bits of shmflg specify the permissions granted to the owner, group, and others.
  39. These bits have the same format, and the same meaning, as the mode argument of open(2). Presently, execute permissions are not used by
  40. the system.
  41. When a new shared memory segment is created, its contents are initialized to zero values, and its associated data structure, shmid_ds
  42. (see shmctl(2)), is initialized as follows:
  43. • shm_perm.cuid and shm_perm.uid are set to the effective user ID of the calling process.
  44. • shm_perm.cgid and shm_perm.gid are set to the effective group ID of the calling process.
  45. • The least significant 9 bits of shm_perm.mode are set to the least significant 9 bit of shmflg.
  46. • shm_segsz is set to the value of size.
  47. • shm_lpid, shm_nattch, shm_atime, and shm_dtime are set to 0.
  48. • shm_ctime is set to the current time.
  49. If the shared memory segment already exists, the permissions are verified, and a check is made to see if it is marked for destruction.
  50. RETURN VALUE
  51. On success, a valid shared memory identifier is returned. On error, -1 is returned, and errno is set to indicate the error.
  52. ERRORS
  53. On failure, errno is set to one of the following:
  54. EACCES The user does not have permission to access the shared memory segment, and does not have the CAP_IPC_OWNER capability in the user
  55. namespace that governs its IPC namespace.
  56. EEXIST IPC_CREAT and IPC_EXCL were specified in shmflg, but a shared memory segment already exists for key.
  57. EINVAL A new segment was to be created and size is less than SHMMIN or greater than SHMMAX.
  58. EINVAL A segment for the given key exists, but size is greater than the size of that segment.
  59. ENFILE The system-wide limit on the total number of open files has been reached.
  60. ENOENT No segment exists for the given key, and IPC_CREAT was not specified.
  61. ENOMEM No memory could be allocated for segment overhead.
  62. ENOSPC All possible shared memory IDs have been taken (SHMMNI), or allocating a segment of the requested size would cause the system to
  63. exceed the system-wide limit on shared memory (SHMALL).
  64. EPERM The SHM_HUGETLB flag was specified, but the caller was not privileged (did not have the CAP_IPC_LOCK capability).
  65. CONFORMING TO
  66. POSIX.1-2001, POSIX.1-2008, SVr4.
  67. SHM_HUGETLB and SHM_NORESERVE are Linux extensions.
  68. NOTES
  69. The inclusion of <sys/types.h> and <sys/ipc.h> isn't required on Linux or by any version of POSIX. However, some old implementations re‐
  70. quired the inclusion of these header files, and the SVID also documented their inclusion. Applications intended to be portable to such
  71. old systems may need to include these header files.
  72. IPC_PRIVATE isn't a flag field but a key_t type. If this special value is used for key, the system call ignores all but the least sig‐
  73. nificant 9 bits of shmflg and creates a new shared memory segment.
  74. Shared memory limits
  75. The following limits on shared memory segment resources affect the shmget() call:
  76. SHMALL System-wide limit on the total amount of shared memory, measured in units of the system page size.
  77. On Linux, this limit can be read and modified via /proc/sys/kernel/shmall. Since Linux 3.16, the default value for this limit is:
  78. ULONG_MAX - 2^24
  79. The effect of this value (which is suitable for both 32-bit and 64-bit systems) is to impose no limitation on allocations. This
  80. value, rather than ULONG_MAX, was chosen as the default to prevent some cases where historical applications simply raised the ex‐
  81. isting limit without first checking its current value. Such applications would cause the value to overflow if the limit was set
  82. at ULONG_MAX.
  83. From Linux 2.4 up to Linux 3.15, the default value for this limit was:
  84. SHMMAX / PAGE_SIZE * (SHMMNI / 16)
  85. If SHMMAX and SHMMNI were not modified, then multiplying the result of this formula by the page size (to get a value in bytes)
  86. yielded a value of 8 GB as the limit on the total memory used by all shared memory segments.
  87. SHMMAX Maximum size in bytes for a shared memory segment.
  88. On Linux, this limit can be read and modified via /proc/sys/kernel/shmmax. Since Linux 3.16, the default value for this limit is:
  89. ULONG_MAX - 2^24
  90. The effect of this value (which is suitable for both 32-bit and 64-bit systems) is to impose no limitation on allocations. See
  91. the description of SHMALL for a discussion of why this default value (rather than ULONG_MAX) is used.
  92. From Linux 2.2 up to Linux 3.15, the default value of this limit was 0x2000000 (32 MB).
  93. Because it is not possible to map just part of a shared memory segment, the amount of virtual memory places another limit on the
  94. maximum size of a usable segment: for example, on i386 the largest segments that can be mapped have a size of around 2.8 GB, and
  95. on x86-64 the limit is around 127 TB.
  96. SHMMIN Minimum size in bytes for a shared memory segment: implementation dependent (currently 1 byte, though PAGE_SIZE is the effective
  97. minimum size).
  98. SHMMNI System-wide limit on the number of shared memory segments. In Linux 2.2, the default value for this limit was 128; since Linux
  99. 2.4, the default value is 4096.
  100. On Linux, this limit can be read and modified via /proc/sys/kernel/shmmni.
  101. The implementation has no specific limits for the per-process maximum number of shared memory segments (SHMSEG).
  102. Linux notes
  103. Until version 2.3.30, Linux would return EIDRM for a shmget() on a shared memory segment scheduled for deletion.
  104. BUGS
  105. The name choice IPC_PRIVATE was perhaps unfortunate, IPC_NEW would more clearly show its function.
  106. EXAMPLES
  107. See shmop(2).
  108. SEE ALSO
  109. memfd_create(2), shmat(2), shmctl(2), shmdt(2), ftok(3), capabilities(7), shm_overview(7), sysvipc(7)
  110. COLOPHON
  111. This page is part of release 5.10 of the Linux man-pages project. A description of the project, information about reporting bugs, and
  112. the latest version of this page, can be found at https://www.kernel.org/doc/man-pages/.
  113. Linux 2020-04-11 SHMGET(2)

man shmdt

  1. SHMOP(2) Linux Programmer's Manual SHMOP(2)
  2. NAME
  3. shmat, shmdt - System V shared memory operations
  4. SYNOPSIS
  5. #include <sys/types.h>
  6. #include <sys/shm.h>
  7. void *shmat(int shmid, const void *shmaddr, int shmflg);
  8. int shmdt(const void *shmaddr);
  9. DESCRIPTION
  10. shmat()
  11. shmat() attaches the System V shared memory segment identified by shmid to the address space of the calling process. The attaching ad‐
  12. dress is specified by shmaddr with one of the following criteria:
  13. • If shmaddr is NULL, the system chooses a suitable (unused) page-aligned address to attach the segment.
  14. • If shmaddr isn't NULL and SHM_RND is specified in shmflg, the attach occurs at the address equal to shmaddr rounded down to the nearest
  15. multiple of SHMLBA.
  16. • Otherwise, shmaddr must be a page-aligned address at which the attach occurs.
  17. In addition to SHM_RND, the following flags may be specified in the shmflg bit-mask argument:
  18. SHM_EXEC (Linux-specific; since Linux 2.6.9)
  19. Allow the contents of the segment to be executed. The caller must have execute permission on the segment.
  20. SHM_RDONLY
  21. Attach the segment for read-only access. The process must have read permission for the segment. If this flag is not specified,
  22. the segment is attached for read and write access, and the process must have read and write permission for the segment. There is
  23. no notion of a write-only shared memory segment.
  24. SHM_REMAP (Linux-specific)
  25. This flag specifies that the mapping of the segment should replace any existing mapping in the range starting at shmaddr and con‐
  26. tinuing for the size of the segment. (Normally, an EINVAL error would result if a mapping already exists in this address range.)
  27. In this case, shmaddr must not be NULL.
  28. The brk(2) value of the calling process is not altered by the attach. The segment will automatically be detached at process exit. The
  29. same segment may be attached as a read and as a read-write one, and more than once, in the process's address space.
  30. A successful shmat() call updates the members of the shmid_ds structure (see shmctl(2)) associated with the shared memory segment as fol‐
  31. lows:
  32. • shm_atime is set to the current time.
  33. • shm_lpid is set to the process-ID of the calling process.
  34. • shm_nattch is incremented by one.
  35. shmdt()
  36. shmdt() detaches the shared memory segment located at the address specified by shmaddr from the address space of the calling process.
  37. The to-be-detached segment must be currently attached with shmaddr equal to the value returned by the attaching shmat() call.
  38. On a successful shmdt() call, the system updates the members of the shmid_ds structure associated with the shared memory segment as fol‐
  39. lows:
  40. • shm_dtime is set to the current time.
  41. • shm_lpid is set to the process-ID of the calling process.
  42. • shm_nattch is decremented by one. If it becomes 0 and the segment is marked for deletion, the segment is deleted.
  43. RETURN VALUE
  44. On success, shmat() returns the address of the attached shared memory segment; on error, (void *) -1 is returned, and errno is set to in‐
  45. dicate the cause of the error.
  46. On success, shmdt() returns 0; on error -1 is returned, and errno is set to indicate the cause of the error.
  47. ERRORS
  48. When shmat() fails, errno is set to one of the following:
  49. EACCES The calling process does not have the required permissions for the requested attach type, and does not have the CAP_IPC_OWNER ca‐
  50. pability in the user namespace that governs its IPC namespace.
  51. EIDRM shmid points to a removed identifier.
  52. EINVAL Invalid shmid value, unaligned (i.e., not page-aligned and SHM_RND was not specified) or invalid shmaddr value, or can't attach
  53. segment at shmaddr, or SHM_REMAP was specified and shmaddr was NULL.
  54. ENOMEM Could not allocate memory for the descriptor or for the page tables.
  55. When shmdt() fails, errno is set as follows:
  56. EINVAL There is no shared memory segment attached at shmaddr; or, shmaddr is not aligned on a page boundary.
  57. CONFORMING TO
  58. POSIX.1-2001, POSIX.1-2008, SVr4.
  59. In SVID 3 (or perhaps earlier), the type of the shmaddr argument was changed from char * into const void *, and the returned type of
  60. shmat() from char * into void *.
  61. NOTES
  62. After a fork(2), the child inherits the attached shared memory segments.
  63. After an execve(2), all attached shared memory segments are detached from the process.
  64. Upon _exit(2), all attached shared memory segments are detached from the process.
  65. Using shmat() with shmaddr equal to NULL is the preferred, portable way of attaching a shared memory segment. Be aware that the shared
  66. memory segment attached in this way may be attached at different addresses in different processes. Therefore, any pointers maintained
  67. within the shared memory must be made relative (typically to the starting address of the segment), rather than absolute.
  68. On Linux, it is possible to attach a shared memory segment even if it is already marked to be deleted. However, POSIX.1 does not specify
  69. this behavior and many other implementations do not support it.
  70. The following system parameter affects shmat():
  71. SHMLBA Segment low boundary address multiple. When explicitly specifying an attach address in a call to shmat(), the caller should en‐
  72. sure that the address is a multiple of this value. This is necessary on some architectures, in order either to ensure good CPU
  73. cache performance or to ensure that different attaches of the same segment have consistent views within the CPU cache. SHMLBA is
  74. normally some multiple of the system page size. (On many Linux architectures, SHMLBA is the same as the system page size.)
  75. The implementation places no intrinsic per-process limit on the number of shared memory segments (SHMSEG).
  76. EXAMPLES
  77. The two programs shown below exchange a string using a shared memory segment. Further details about the programs are given below.
  78. First, we show a shell session demonstrating their use.
  79. In one terminal window, we run the "reader" program, which creates a System V shared memory segment and a System V semaphore set. The
  80. program prints out the IDs of the created objects, and then waits for the semaphore to change value.
  81. $ ./svshm_string_read
  82. shmid = 1114194; semid = 15
  83. In another terminal window, we run the "writer" program. The "writer" program takes three command-line arguments: the IDs of the shared
  84. memory segment and semaphore set created by the "reader", and a string. It attaches the existing shared memory segment, copies the
  85. string to the shared memory, and modifies the semaphore value.
  86. $ ./svshm_string_write 1114194 15 'Hello, world'
  87. Returning to the terminal where the "reader" is running, we see that the program has ceased waiting on the semaphore and has printed the
  88. string that was copied into the shared memory segment by the writer:
  89. Hello, world
  90. Program source: svshm_string.h
  91. The following header file is included by the "reader" and "writer" programs.
  92. #include <sys/types.h>
  93. #include <sys/ipc.h>
  94. #include <sys/shm.h>
  95. #include <sys/sem.h>
  96. #include <stdio.h>
  97. #include <stdlib.h>
  98. #include <string.h>
  99. #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
  100. } while (0)
  101. union semun { /* Used in calls to semctl() */
  102. int val;
  103. struct semid_ds * buf;
  104. unsigned short * array;
  105. #if defined(__linux__)
  106. struct seminfo * __buf;
  107. #endif
  108. };
  109. #define MEM_SIZE 4096
  110. Program source: svshm_string_read.c
  111. The "reader" program creates a shared memory segment and a semaphore set containing one semaphore. It then attaches the shared memory
  112. object into its address space and initializes the semaphore value to 1. Finally, the program waits for the semaphore value to become 0,
  113. and afterwards prints the string that has been copied into the shared memory segment by the "writer".
  114. /* svshm_string_read.c
  115. Licensed under GNU General Public License v2 or later.
  116. */
  117. #include "svshm_string.h"
  118. int
  119. main(int argc, char *argv[])
  120. {
  121. int semid, shmid;
  122. union semun arg, dummy;
  123. struct sembuf sop;
  124. char *addr;
  125. /* Create shared memory and semaphore set containing one
  126. semaphore */
  127. shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600);
  128. if (shmid == -1)
  129. errExit("shmget");
  130. semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
  131. if (shmid == -1)
  132. errExit("shmget");
  133. /* Attach shared memory into our address space */
  134. addr = shmat(shmid, NULL, SHM_RDONLY);
  135. if (addr == (void *) -1)
  136. errExit("shmat");
  137. /* Initialize semaphore 0 in set with value 1 */
  138. arg.val = 1;
  139. if (semctl(semid, 0, SETVAL, arg) == -1)
  140. errExit("semctl");
  141. printf("shmid = %d; semid = %d\n", shmid, semid);
  142. /* Wait for semaphore value to become 0 */
  143. sop.sem_num = 0;
  144. sop.sem_op = 0;
  145. sop.sem_flg = 0;
  146. if (semop(semid, &sop, 1) == -1)
  147. errExit("semop");
  148. /* Print the string from shared memory */
  149. printf("%s\n", addr);
  150. /* Remove shared memory and semaphore set */
  151. if (shmctl(shmid, IPC_RMID, NULL) == -1)
  152. errExit("shmctl");
  153. if (semctl(semid, 0, IPC_RMID, dummy) == -1)
  154. errExit("semctl");
  155. exit(EXIT_SUCCESS);
  156. }
  157. Program source: svshm_string_write.c
  158. The writer program takes three command-line arguments: the IDs of the shared memory segment and semaphore set that have already been cre‐
  159. ated by the "reader", and a string. It attaches the shared memory segment into its address space, and then decrements the semaphore
  160. value to 0 in order to inform the "reader" that it can now examine the contents of the shared memory.
  161. /* svshm_string_write.c
  162. Licensed under GNU General Public License v2 or later.
  163. */
  164. #include "svshm_string.h"
  165. int
  166. main(int argc, char *argv[])
  167. {
  168. int semid, shmid;
  169. struct sembuf sop;
  170. char *addr;
  171. size_t len;
  172. if (argc != 4) {
  173. fprintf(stderr, "Usage: %s shmid semid string\n", argv[0]);
  174. exit(EXIT_FAILURE);
  175. }
  176. len = strlen(argv[3]) + 1; /* +1 to include trailing '\0' */
  177. if (len > MEM_SIZE) {
  178. fprintf(stderr, "String is too big!\n");
  179. exit(EXIT_FAILURE);
  180. }
  181. /* Get object IDs from command-line */
  182. shmid = atoi(argv[1]);
  183. semid = atoi(argv[2]);
  184. /* Attach shared memory into our address space and copy string
  185. (including trailing null byte) into memory. */
  186. addr = shmat(shmid, NULL, 0);
  187. if (addr == (void *) -1)
  188. errExit("shmat");
  189. memcpy(addr, argv[3], len);
  190. /* Decrement semaphore to 0 */
  191. sop.sem_num = 0;
  192. sop.sem_op = -1;
  193. sop.sem_flg = 0;
  194. if (semop(semid, &sop, 1) == -1)
  195. errExit("semop");
  196. exit(EXIT_SUCCESS);
  197. }
  198. SEE ALSO
  199. brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), sysvipc(7)
  200. COLOPHON
  201. This page is part of release 5.10 of the Linux man-pages project. A description of the project, information about reporting bugs, and
  202. the latest version of this page, can be found at https://www.kernel.org/doc/man-pages/.
  203. Linux 2020-04-11 SHMOP(2)

man shmat

  1. SHMOP(2) Linux Programmer's Manual SHMOP(2)
  2. NAME
  3. shmat, shmdt - System V shared memory operations
  4. SYNOPSIS
  5. #include <sys/types.h>
  6. #include <sys/shm.h>
  7. void *shmat(int shmid, const void *shmaddr, int shmflg);
  8. int shmdt(const void *shmaddr);
  9. DESCRIPTION
  10. shmat()
  11. shmat() attaches the System V shared memory segment identified by shmid to the address space of the calling process. The attaching ad‐
  12. dress is specified by shmaddr with one of the following criteria:
  13. • If shmaddr is NULL, the system chooses a suitable (unused) page-aligned address to attach the segment.
  14. • If shmaddr isn't NULL and SHM_RND is specified in shmflg, the attach occurs at the address equal to shmaddr rounded down to the nearest
  15. multiple of SHMLBA.
  16. • Otherwise, shmaddr must be a page-aligned address at which the attach occurs.
  17. In addition to SHM_RND, the following flags may be specified in the shmflg bit-mask argument:
  18. SHM_EXEC (Linux-specific; since Linux 2.6.9)
  19. Allow the contents of the segment to be executed. The caller must have execute permission on the segment.
  20. SHM_RDONLY
  21. Attach the segment for read-only access. The process must have read permission for the segment. If this flag is not specified,
  22. the segment is attached for read and write access, and the process must have read and write permission for the segment. There is
  23. no notion of a write-only shared memory segment.
  24. SHM_REMAP (Linux-specific)
  25. This flag specifies that the mapping of the segment should replace any existing mapping in the range starting at shmaddr and con‐
  26. tinuing for the size of the segment. (Normally, an EINVAL error would result if a mapping already exists in this address range.)
  27. In this case, shmaddr must not be NULL.
  28. The brk(2) value of the calling process is not altered by the attach. The segment will automatically be detached at process exit. The
  29. same segment may be attached as a read and as a read-write one, and more than once, in the process's address space.
  30. A successful shmat() call updates the members of the shmid_ds structure (see shmctl(2)) associated with the shared memory segment as fol‐
  31. lows:
  32. • shm_atime is set to the current time.
  33. • shm_lpid is set to the process-ID of the calling process.
  34. • shm_nattch is incremented by one.
  35. shmdt()
  36. shmdt() detaches the shared memory segment located at the address specified by shmaddr from the address space of the calling process.
  37. The to-be-detached segment must be currently attached with shmaddr equal to the value returned by the attaching shmat() call.
  38. On a successful shmdt() call, the system updates the members of the shmid_ds structure associated with the shared memory segment as fol‐
  39. lows:
  40. • shm_dtime is set to the current time.
  41. • shm_lpid is set to the process-ID of the calling process.
  42. • shm_nattch is decremented by one. If it becomes 0 and the segment is marked for deletion, the segment is deleted.
  43. RETURN VALUE
  44. On success, shmat() returns the address of the attached shared memory segment; on error, (void *) -1 is returned, and errno is set to in‐
  45. dicate the cause of the error.
  46. On success, shmdt() returns 0; on error -1 is returned, and errno is set to indicate the cause of the error.
  47. ERRORS
  48. When shmat() fails, errno is set to one of the following:
  49. EACCES The calling process does not have the required permissions for the requested attach type, and does not have the CAP_IPC_OWNER ca‐
  50. pability in the user namespace that governs its IPC namespace.
  51. EIDRM shmid points to a removed identifier.
  52. EINVAL Invalid shmid value, unaligned (i.e., not page-aligned and SHM_RND was not specified) or invalid shmaddr value, or can't attach
  53. segment at shmaddr, or SHM_REMAP was specified and shmaddr was NULL.
  54. ENOMEM Could not allocate memory for the descriptor or for the page tables.
  55. When shmdt() fails, errno is set as follows:
  56. EINVAL There is no shared memory segment attached at shmaddr; or, shmaddr is not aligned on a page boundary.
  57. CONFORMING TO
  58. POSIX.1-2001, POSIX.1-2008, SVr4.
  59. In SVID 3 (or perhaps earlier), the type of the shmaddr argument was changed from char * into const void *, and the returned type of
  60. shmat() from char * into void *.
  61. NOTES
  62. After a fork(2), the child inherits the attached shared memory segments.
  63. After an execve(2), all attached shared memory segments are detached from the process.
  64. Upon _exit(2), all attached shared memory segments are detached from the process.
  65. Using shmat() with shmaddr equal to NULL is the preferred, portable way of attaching a shared memory segment. Be aware that the shared
  66. memory segment attached in this way may be attached at different addresses in different processes. Therefore, any pointers maintained
  67. within the shared memory must be made relative (typically to the starting address of the segment), rather than absolute.
  68. On Linux, it is possible to attach a shared memory segment even if it is already marked to be deleted. However, POSIX.1 does not specify
  69. this behavior and many other implementations do not support it.
  70. The following system parameter affects shmat():
  71. SHMLBA Segment low boundary address multiple. When explicitly specifying an attach address in a call to shmat(), the caller should en‐
  72. sure that the address is a multiple of this value. This is necessary on some architectures, in order either to ensure good CPU
  73. cache performance or to ensure that different attaches of the same segment have consistent views within the CPU cache. SHMLBA is
  74. normally some multiple of the system page size. (On many Linux architectures, SHMLBA is the same as the system page size.)
  75. The implementation places no intrinsic per-process limit on the number of shared memory segments (SHMSEG).
  76. EXAMPLES
  77. The two programs shown below exchange a string using a shared memory segment. Further details about the programs are given below.
  78. First, we show a shell session demonstrating their use.
  79. In one terminal window, we run the "reader" program, which creates a System V shared memory segment and a System V semaphore set. The
  80. program prints out the IDs of the created objects, and then waits for the semaphore to change value.
  81. $ ./svshm_string_read
  82. shmid = 1114194; semid = 15
  83. In another terminal window, we run the "writer" program. The "writer" program takes three command-line arguments: the IDs of the shared
  84. memory segment and semaphore set created by the "reader", and a string. It attaches the existing shared memory segment, copies the
  85. string to the shared memory, and modifies the semaphore value.
  86. $ ./svshm_string_write 1114194 15 'Hello, world'
  87. Returning to the terminal where the "reader" is running, we see that the program has ceased waiting on the semaphore and has printed the
  88. string that was copied into the shared memory segment by the writer:
  89. Hello, world
  90. Program source: svshm_string.h
  91. The following header file is included by the "reader" and "writer" programs.
  92. #include <sys/types.h>
  93. #include <sys/ipc.h>
  94. #include <sys/shm.h>
  95. #include <sys/sem.h>
  96. #include <stdio.h>
  97. #include <stdlib.h>
  98. #include <string.h>
  99. #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
  100. } while (0)
  101. union semun { /* Used in calls to semctl() */
  102. int val;
  103. struct semid_ds * buf;
  104. unsigned short * array;
  105. #if defined(__linux__)
  106. struct seminfo * __buf;
  107. #endif
  108. };
  109. #define MEM_SIZE 4096
  110. Program source: svshm_string_read.c
  111. The "reader" program creates a shared memory segment and a semaphore set containing one semaphore. It then attaches the shared memory
  112. object into its address space and initializes the semaphore value to 1. Finally, the program waits for the semaphore value to become 0,
  113. and afterwards prints the string that has been copied into the shared memory segment by the "writer".
  114. /* svshm_string_read.c
  115. Licensed under GNU General Public License v2 or later.
  116. */
  117. #include "svshm_string.h"
  118. int
  119. main(int argc, char *argv[])
  120. {
  121. int semid, shmid;
  122. union semun arg, dummy;
  123. struct sembuf sop;
  124. char *addr;
  125. /* Create shared memory and semaphore set containing one
  126. semaphore */
  127. shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600);
  128. if (shmid == -1)
  129. errExit("shmget");
  130. semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
  131. if (shmid == -1)
  132. errExit("shmget");
  133. /* Attach shared memory into our address space */
  134. addr = shmat(shmid, NULL, SHM_RDONLY);
  135. if (addr == (void *) -1)
  136. errExit("shmat");
  137. /* Initialize semaphore 0 in set with value 1 */
  138. arg.val = 1;
  139. if (semctl(semid, 0, SETVAL, arg) == -1)
  140. errExit("semctl");
  141. printf("shmid = %d; semid = %d\n", shmid, semid);
  142. /* Wait for semaphore value to become 0 */
  143. sop.sem_num = 0;
  144. sop.sem_op = 0;
  145. sop.sem_flg = 0;
  146. if (semop(semid, &sop, 1) == -1)
  147. errExit("semop");
  148. /* Print the string from shared memory */
  149. printf("%s\n", addr);
  150. /* Remove shared memory and semaphore set */
  151. if (shmctl(shmid, IPC_RMID, NULL) == -1)
  152. errExit("shmctl");
  153. if (semctl(semid, 0, IPC_RMID, dummy) == -1)
  154. errExit("semctl");
  155. exit(EXIT_SUCCESS);
  156. }
  157. Program source: svshm_string_write.c
  158. The writer program takes three command-line arguments: the IDs of the shared memory segment and semaphore set that have already been cre‐
  159. ated by the "reader", and a string. It attaches the shared memory segment into its address space, and then decrements the semaphore
  160. value to 0 in order to inform the "reader" that it can now examine the contents of the shared memory.
  161. /* svshm_string_write.c
  162. Licensed under GNU General Public License v2 or later.
  163. */
  164. #include "svshm_string.h"
  165. int
  166. main(int argc, char *argv[])
  167. {
  168. int semid, shmid;
  169. struct sembuf sop;
  170. char *addr;
  171. size_t len;
  172. if (argc != 4) {
  173. fprintf(stderr, "Usage: %s shmid semid string\n", argv[0]);
  174. exit(EXIT_FAILURE);
  175. }
  176. len = strlen(argv[3]) + 1; /* +1 to include trailing '\0' */
  177. if (len > MEM_SIZE) {
  178. fprintf(stderr, "String is too big!\n");
  179. exit(EXIT_FAILURE);
  180. }
  181. /* Get object IDs from command-line */
  182. shmid = atoi(argv[1]);
  183. semid = atoi(argv[2]);
  184. /* Attach shared memory into our address space and copy string
  185. (including trailing null byte) into memory. */
  186. addr = shmat(shmid, NULL, 0);
  187. if (addr == (void *) -1)
  188. errExit("shmat");
  189. memcpy(addr, argv[3], len);
  190. /* Decrement semaphore to 0 */
  191. sop.sem_num = 0;
  192. sop.sem_op = -1;
  193. sop.sem_flg = 0;
  194. if (semop(semid, &sop, 1) == -1)
  195. errExit("semop");
  196. exit(EXIT_SUCCESS);
  197. }
  198. SEE ALSO
  199. brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), sysvipc(7)
  200. COLOPHON
  201. This page is part of release 5.10 of the Linux man-pages project. A description of the project, information about reporting bugs, and
  202. the latest version of this page, can be found at https://www.kernel.org/doc/man-pages/.
  203. Linux 2020-04-11 SHMOP(2)

 共享内存示例 12.1c

  1. #include <stdio.h>
  2. #include <sys/ipc.h>
  3. #include <sys/shm.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. #include <sys/wait.h>
  8. char msg[] = "Hello world";
  9. int main(void)
  10. {
  11. int shmid;
  12. pid_t pid;
  13. shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT);
  14. pid = fork();
  15. if(pid > 0)
  16. {
  17. char *p_addr;
  18. p_addr = shmat(shmid, NULL, 0);
  19. memset(p_addr, '\0', sizeof(msg));
  20. memcpy(p_addr, msg, sizeof(msg));
  21. shmdt(p_addr);
  22. waitpid(pid, NULL, 0);
  23. }
  24. else if(pid == 0)
  25. {
  26. char *c_addr;
  27. c_addr = shmat(shmid, NULL, 0);
  28. printf("Child process waits a short time: \n");
  29. sleep(3);
  30. printf("Child Process reads from shared memory: %s\n", c_addr);
  31. shmdt(c_addr);
  32. }
  33. else
  34. perror("fork");
  35. return 0;
  36. }

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号