赞
踩
目录
程序:(静态的概念)
源代码
指令
进程:(动态的概念)
运行着的程序
创建销毁 耗费资源大
进程间独立
多个进程可以是一个程序
由内核定义 抽象的实体 开辟一系列资源
内部的数据结构
内存
进程的状态信息
有id号
任务:
具体要做的事情
进程做或线程做
为什么引入线程?
当要完成一项任务,进程被内核创建 结束时资源被内核回收 进程销毁。这段过程十分地浪费cpu资源 会给liunx系统内核带来非常大的系统消耗。
线程:
由进程创建 速度比创建进程快
线程从属于进程,一个进程可以有多个线程
线程之间共享进程的资源
某一个线程崩溃 其他会受到影响
创建销毁线程 耗费资源小
一个程序可以创建多个进程
每个进程做一件事情
多个进程也可以调用同一个程序
属调用的资源
实践 获取进程pid
pid = process id
查看getpid的用户手册
man getpid
- GETPID(2) Linux Programmer's Manual GETPID(2)
- NAME
- getpid, getppid - get process identification
- SYNOPSIS
- #include <sys/types.h>
- #include <unistd.h>
- pid_t getpid(void);
- pid_t getppid(void);
- DESCRIPTION
- getpid() returns the process ID (PID) of the calling process. (This is
- often used by routines that generate unique temporary filenames.)
- getppid() returns the process ID of the parent of the calling process.
- This will be either the ID of the process that created this process using
- fork(), or, if that process has already terminated, the ID of the process
- to which this process has been reparented (either init(1) or a "subreaper"
- process defined via the prctl(2) PR_SET_CHILD_SUBREAPER operation).
- ERRORS
- These functions are always successful.
- CONFORMING TO
- POSIX.1-2001, POSIX.1-2008, 4.3BSD, SVr4.
- NOTES
- If the caller's parent is in a different PID namespace (see pid_name‐
- spaces(7)), getppid() returns 0.
-
- From a kernel perspective, the PID (which is shared by all of the threads
- in a multithreaded process) is sometimes also known as the thread group ID
- (TGID). This contrasts with the kernel thread ID (TID), which is unique
- for each thread. For further details, see gettid(2) and the discussion of
- the CLONE_THREAD flag in clone(2).
-
- C library/kernel differences
- From glibc version 2.3.4 up to and including version 2.24, the glibc wrap‐
- per function for getpid() cached PIDs, with the goal of avoiding addi‐
- tional system calls when a process calls getpid() repeatedly. Normally
- this caching was invisible, but its correct operation relied on support in
- the wrapper functions for fork(2), vfork(2), and clone(2): if an applica‐
- tion bypassed the glibc wrappers for these system calls by using
- syscall(2), then a call to getpid() in the child would return the wrong
- value (to be precise: it would return the PID of the parent process). In
- addition, there were cases where getpid() could return the wrong value
- even when invoking clone(2) via the glibc wrapper function. (For a dis‐
- cussion of one such case, see BUGS in clone(2).) Furthermore, the com‐
- plexity of the caching code had been the source of a few bugs within glibc
- over the years.
-
- Because of the aforementioned problems, since glibc version 2.25, the PID
- cache is removed: calls to getpid() always invoke the actual system call,
- rather than returning a cached value.
-
- On Alpha, instead of a pair of getpid() and getppid() system calls, a sin‐
- gle getxpid() system call is provided, which returns a pair of PID and
- parent PID. The glibc getpid() and getppid() wrapper functions transpar‐
- ently deal with this. See syscall(2) for details regarding register map‐
- ping.
-
- SEE ALSO
- clone(2), fork(2), gettid(2), kill(2), exec(3), mkstemp(3), tempnam(3),
- tmpfile(3), tmpnam(3), credentials(7), pid_namespaces(7)
-
- COLOPHON
- This page is part of release 5.10 of the Linux man-pages project. A de‐
- scription of the project, information about reporting bugs, and the latest
- version of this page, can be found at
- https://www.kernel.org/doc/man-pages/.
-
- Linux 2020-11-01 GETPID(2)
getpid() 当前进程
getppid() 父进程
getpid代码示例01.1
- #include<sys/types.h>
- #include<unistd.h>
- #include<stdio.h>
-
- int main(void)
- {
- pid_t pid;
- while(1)
- {
- printf("pid=%d\n",getpid());
- printf("ppid=%d\n",getppid());
- printf("hello world\n");
- sleep(1);
- }
- return 0;
- }
--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)(历史)(一回事)
使用fork创建进程
查看手册man fork()
- FORK(2) Linux Programmer's Manual FORK(2)
- NAME
- fork - create a child process
- SYNOPSIS
- #include <sys/types.h>
- #include <unistd.h>
- pid_t fork(void);
-
- DESCRIPTION
- fork() creates a new process by duplicating the calling process. The new process is referred to
- as the child process. The calling process is referred to as the parent process.
- The child process and the parent process run in separate memory spaces. At the time of fork()
- both memory spaces have the same content. Memory writes, file mappings (mmap(2)), and unmappings
- (munmap(2)) performed by one of the processes do not affect the other.
- The child process is an exact duplicate of the parent process except for the following points:
- * The child has its own unique process ID, and this PID does not match the ID of any existing
- process group (setpgid(2)) or session.
- * The child's parent process ID is the same as the parent's process ID.
- * The child does not inherit its parent's memory locks (mlock(2), mlockall(2)).
- * Process resource utilizations (getrusage(2)) and CPU time counters (times(2)) are reset to
- zero in the child.
- * The child's set of pending signals is initially empty (sigpending(2)).
- * The child does not inherit semaphore adjustments from its parent (semop(2)).
- * The child does not inherit process-associated record locks from its parent (fcntl(2)). (On
- the other hand, it does inherit fcntl(2) open file description locks and flock(2) locks from
- its parent.)
- * The child does not inherit timers from its parent (setitimer(2), alarm(2), timer_create(2)).
- * The child does not inherit outstanding asynchronous I/O operations from its parent
- (aio_read(3), aio_write(3)), nor does it inherit any asynchronous I/O contexts from its parent
- (see io_setup(2)).
- The process attributes in the preceding list are all specified in POSIX.1. The parent and child
- also differ with respect to the following Linux-specific process attributes:
- * The child does not inherit directory change notifications (dnotify) from its parent (see the
- description of F_NOTIFY in fcntl(2)).
- * The prctl(2) PR_SET_PDEATHSIG setting is reset so that the child does not receive a signal
- when its parent terminates.
- * The default timer slack value is set to the parent's current timer slack value. See the de‐
- scription of PR_SET_TIMERSLACK in prctl(2).
- * Memory mappings that have been marked with the madvise(2) MADV_DONTFORK flag are not inherited
- across a fork().
- * Memory in address ranges that have been marked with the madvise(2) MADV_WIPEONFORK flag is ze‐
- roed in the child after a fork(). (The MADV_WIPEONFORK setting remains in place for those ad‐
- dress ranges in the child.)
- * The termination signal of the child is always SIGCHLD (see clone(2)).
- * The port access permission bits set by ioperm(2) are not inherited by the child; the child
- must turn on any bits that it requires using ioperm(2).
- Note the following further points:
- * The child process is created with a single thread—the one that called fork(). The entire vir‐
- tual address space of the parent is replicated in the child, including the states of mutexes,
- condition variables, and other pthreads objects; the use of pthread_atfork(3) may be helpful
- for dealing with problems that this can cause.
- * After a fork() in a multithreaded program, the child can safely call only async-signal-safe
- functions (see signal-safety(7)) until such time as it calls execve(2).
- * The child inherits copies of the parent's set of open file descriptors. Each file descriptor
- in the child refers to the same open file description (see open(2)) as the corresponding file
- descriptor in the parent. This means that the two file descriptors share open file status
- flags, file offset, and signal-driven I/O attributes (see the description of F_SETOWN and
- F_SETSIG in fcntl(2)).
- * The child inherits copies of the parent's set of open message queue descriptors (see mq_over‐
- view(7)). Each file descriptor in the child refers to the same open message queue description
- as the corresponding file descriptor in the parent. This means that the two file descriptors
- share the same flags (mq_flags).
- * The child inherits copies of the parent's set of open directory streams (see opendir(3)).
- POSIX.1 says that the corresponding directory streams in the parent and child may share the
- directory stream positioning; on Linux/glibc they do not.
-
- RETURN VALUE
- On success, the PID of the child process is returned in the parent, and 0 is returned in the
- child. On failure, -1 is returned in the parent, no child process is created, and errno is set
- appropriately.
-
- ERRORS
- EAGAIN A system-imposed limit on the number of threads was encountered. There are a number of
- limits that may trigger this error:
-
- * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)), which limits the number of
- processes and threads for a real user ID, was reached;
-
- * the kernel's system-wide limit on the number of processes and threads, /proc/sys/ker‐
- nel/threads-max, was reached (see proc(5));
-
- * the maximum number of PIDs, /proc/sys/kernel/pid_max, was reached (see proc(5)); or
- * the PID limit (pids.max) imposed by the cgroup "process number" (PIDs) controller was
- reached.
- EAGAIN The caller is operating under the SCHED_DEADLINE scheduling policy and does not have the
- reset-on-fork flag set. See sched(7).
- ENOMEM fork() failed to allocate the necessary kernel structures because memory is tight.
- ENOMEM An attempt was made to create a child process in a PID namespace whose "init" process has
- terminated. See pid_namespaces(7).
- ENOSYS fork() is not supported on this platform (for example, hardware without a Memory-Manage‐
- ment Unit).
- ERESTARTNOINTR (since Linux 2.6.17)
- System call was interrupted by a signal and will be restarted. (This can be seen only
- during a trace.)
- CONFORMING TO
- POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.
- NOTES
- Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs
- is the time and memory required to duplicate the parent's page tables, and to create a unique
- task structure for the child.
- C library/kernel differences
- Since version 2.3.3, rather than invoking the kernel's fork() system call, the glibc fork() wrap‐
- per that is provided as part of the NPTL threading implementation invokes clone(2) with flags
- that provide the same effect as the traditional system call. (A call to fork() is equivalent to
- a call to clone(2) specifying flags as just SIGCHLD.) The glibc wrapper invokes any fork han‐
- dlers that have been established using pthread_atfork(3).
- EXAMPLES
- See pipe(2) and wait(2).
- SEE ALSO
- clone(2), execve(2), exit(2), setrlimit(2), unshare(2), vfork(2), wait(2), daemon(3), pthread_at‐
- fork(3), capabilities(7), credentials(7)
- COLOPHON
- This page is part of release 5.10 of the Linux man-pages project. A description of the project,
- information about reporting bugs, and the latest version of this page, can be found at
- https://www.kernel.org/doc/man-pages/.
- Linux 2020-06-09 FORK(2)
fork代码示例02.1
- #include<sys/types.h>
- #include<unistd.h>
- #include<stdio.h>
- int main(void)
- {
- pid_t pid;
- pid=fork();
- printf("pid=%d\n",pid);
- printf("hello world\n");
- return 0;
- }
fork代码示例02.2
- #include<sys/types.h>
- #include<unistd.h>
- #include <stdio.h>
- int main(void)
- {
- pid_t pid1,pid2;
- pid1=fork();
- pid2=fork();
- printf("pid1=%d,pid2=%d\n",pid1,pid2);
- while(1);
- return 0;
- }
输出
:~/Desktop# ./a.out
pid1=24387B,pid2=24388C
pid1=24387B,pid2=0
pid1=0,pid2=24389D
pid1=0,pid2=0
分析程序执行的流程
加入循环 调出进程树 pstree -p
可以分析进程id大概就是这样执行的 不过进程之间是独立的 不一定谁先执行,
为什么用到多进程?
希望父 子进程(独立分割)执行不同的内容
并发执行代码示例03.1
- #include<sys/types.h>
- #include<unistd.h>
- #include <stdio.h>
- int main(void)
- {
- pid_t pid;
- pid=fork();
- if(pid>0){ //父进程
- while(1){
- printf("hello world\n");
- sleep(1);
- }
- }
- else if(pid==0){
- while(1){
- printf("good moring\n");
- sleep(1);
- }
- }
- else{
- printf("err\n");
- }
- return 0;
- }
Hello world 和 good moring 并行执行
不能根据输出结果 判断谁先执行
微观:默认情况下(内核) 父进程先调用
父进程在创建 子进程的过程 正在执行中
父进程的结束 不会影响子进程的执行?
状态影响
状态影响代码示例03.2
- #include<sys/types.h>
- #include<unistd.h>
- #include <stdio.h>
- int main(void)
- {
- pid_t pid;
- int count = 0;
- pid=fork();
- if(pid>0){ //父进程
- for(int i=0;i<10;i++){
-
- printf("hello world count=%d\n",count++);
- sleep(1);}
- }
- else if(pid==0){
- while(1){
- printf("good moring count=%d\n",count++);
- sleep(1);
- }
- }
- else{
- printf("err\n");
- }
- return 0;
- }
输出
可以看出父进程的结束 并没有影响的子进程的执行状态。
...........................................................................................................................................................
有没有手段!进程同步监控子进程的状态...
怎样才能影响!任务之间的通信和同步...
父进程监控子进程状态的改变(结束;停止;)
man wait
- WAIT(1POSIX) POSIX Programmer's Manual WAIT(1POSIX)
- PROLOG
- This manual page is part of the POSIX Programmer's Manual. The Linux implementation of this
- interface may differ (consult the corresponding Linux manual page for details of Linux behav‐
- ior), or the interface may not be implemented on Linux.
- NAME
- wait — await process completion
- SYNOPSIS
- wait [pid...]
- DESCRIPTION
- When an asynchronous list (see Section 2.9.3.1, Examples) is started by the shell, the process
- ID of the last command in each element of the asynchronous list shall become known in the cur‐
- rent shell execution environment; see Section 2.12, Shell Execution Environment.
-
- If the wait utility is invoked with no operands, it shall wait until all process IDs known to
- the invoking shell have terminated and exit with a zero exit status.
-
- If one or more pid operands are specified that represent known process IDs, the wait utility
- shall wait until all of them have terminated. If one or more pid operands are specified that
- represent unknown process IDs, wait shall treat them as if they were known process IDs that
- exited with exit status 127. The exit status returned by the wait utility shall be the exit
- status of the process requested by the last pid operand.
-
- The known process IDs are applicable only for invocations of wait in the current shell execu‐
- tion environment.
-
- OPTIONS
- None.
-
- OPERANDS
- The following operand shall be supported:
-
- pid One of the following:
-
- 1. The unsigned decimal integer process ID of a command, for which the utility is
- to wait for the termination.
-
- 2. A job control job ID (see the Base Definitions volume of POSIX.1‐2017, Section
- 3.204, Job Control Job ID) that identifies a background process group to be
- waited for. The job control job ID notation is applicable only for invocations
- of wait in the current shell execution environment; see Section 2.12, Shell Exe‐
- cution Environment. The exit status of wait shall be determined by the last
- command in the pipeline.
-
- Note: The job control job ID type of pid is only available on systems sup‐
- porting the User Portability Utilities option.
-
- STDIN
- Not used.
-
- INPUT FILES
- None.
-
- ENVIRONMENT VARIABLES
- The following environment variables shall affect the execution of wait:
-
- LANG Provide a default value for the internationalization variables that are unset or
- null. (See the Base Definitions volume of POSIX.1‐2017, Section 8.2, International‐
- ization Variables for the precedence of internationalization variables used to de‐
- termine the values of locale categories.)
-
- LC_ALL If set to a non-empty string value, override the values of all the other interna‐
- tionalization variables.
-
- LC_CTYPE Determine the locale for the interpretation of sequences of bytes of text data as
- characters (for example, single-byte as opposed to multi-byte characters in argu‐
- ments).
- LC_MESSAGES
- Determine the locale that should be used to affect the format and contents of diag‐
- nostic messages written to standard error.
- NLSPATH Determine the location of message catalogs for the processing of LC_MESSAGES.
- ASYNCHRONOUS EVENTS
- Default.
- STDOUT
- Not used.
- STDERR
- The standard error shall be used only for diagnostic messages.
- OUTPUT FILES
- None.
- EXTENDED DESCRIPTION
- None.
- EXIT STATUS
- If one or more operands were specified, all of them have terminated or were not known by the
- invoking shell, and the status of the last operand specified is known, then the exit status of
- wait shall be the exit status information of the command indicated by the last operand speci‐
- fied. If the process terminated abnormally due to the receipt of a signal, the exit status
- shall be greater than 128 and shall be distinct from the exit status generated by other sig‐
- nals, but the exact value is unspecified. (See the kill -l option.) Otherwise, the wait util‐
- ity shall exit with one of the following values:
- 0 The wait utility was invoked with no operands and all process IDs known by the invok‐
- ing shell have terminated.
- 1‐126 The wait utility detected an error.
- 127 The command identified by the last pid operand specified is unknown.
- CONSEQUENCES OF ERRORS
- Default.
- The following sections are informative.
- APPLICATION USAGE
- On most implementations, wait is a shell built-in. If it is called in a subshell or separate
- utility execution environment, such as one of the following:
- (wait)
- nohup wait ...
- find . -exec wait ... \;
-
- it returns immediately because there are no known process IDs to wait for in those environ‐
- ments.
-
- Historical implementations of interactive shells have discarded the exit status of terminated
- background processes before each shell prompt. Therefore, the status of background processes
- was usually lost unless it terminated while wait was waiting for it. This could be a serious
- problem when a job that was expected to run for a long time actually terminated quickly with a
- syntax or initialization error because the exit status returned was usually zero if the re‐
- quested process ID was not found. This volume of POSIX.1‐2017 requires the implementation to
- keep the status of terminated jobs available until the status is requested, so that scripts
- like:
-
- j1&
- p1=$!
- j2&
- wait $p1
- echo Job 1 exited with status $?
- wait $!
- echo Job 2 exited with status $?
-
- work without losing status on any of the jobs. The shell is allowed to discard the status of
- any process if it determines that the application cannot get the process ID for that process
- from the shell. It is also required to remember only {CHILD_MAX} number of processes in this
- way. Since the only way to get the process ID from the shell is by using the '!' shell param‐
- eter, the shell is allowed to discard the status of an asynchronous list if "$!" was not ref‐
- erenced before another asynchronous list was started. (This means that the shell only has to
- keep the status of the last asynchronous list started if the application did not reference
- "$!". If the implementation of the shell is smart enough to determine that a reference to
- "$!" was not saved anywhere that the application can retrieve it later, it can use this infor‐
- mation to trim the list of saved information. Note also that a successful call to wait with no
- operands discards the exit status of all asynchronous lists.)
-
- If the exit status of wait is greater than 128, there is no way for the application to know if
- the waited-for process exited with that value or was killed by a signal. Since most utilities
- exit with small values, there is seldom any ambiguity. Even in the ambiguous cases, most ap‐
- plications just need to know that the asynchronous job failed; it does not matter whether it
- detected an error and failed or was killed and did not complete its job normally.
-
- EXAMPLES
- Although the exact value used when a process is terminated by a signal is unspecified, if it
- is known that a signal terminated a process, a script can still reliably determine which sig‐
- nal by using kill as shown by the following script:
-
- sleep 1000&
- pid=$!
- kill -kill $pid
- wait $pid
- echo $pid was terminated by a SIG$(kill -l $?) signal.
-
- If the following sequence of commands is run in less than 31 seconds:
-
- sleep 257 | sleep 31 &
- jobs -l %%
-
- either of the following commands returns the exit status of the second sleep in the pipeline:
-
- wait <pid of sleep 31>
- wait %%
-
- RATIONALE
- The description of wait does not refer to the waitpid() function from the System Interfaces
- volume of POSIX.1‐2017 because that would needlessly overspecify this interface. However, the
- wording means that wait is required to wait for an explicit process when it is given an argu‐
- ment so that the status information of other processes is not consumed. Historical implementa‐
- tions use the wait() function defined in the System Interfaces volume of POSIX.1‐2017 until
- wait() returns the requested process ID or finds that the requested process does not exist.
- Because this means that a shell script could not reliably get the status of all background
- children if a second background job was ever started before the first job finished, it is rec‐
- ommended that the wait utility use a method such as the functionality provided by the wait‐
- pid() function.
-
- The ability to wait for multiple pid operands was adopted from the KornShell.
-
- This new functionality was added because it is needed to determine the exit status of any
- asynchronous list accurately. The only compatibility problem that this change creates is for a
- script like
-
- while sleep 60 do
- job& echo Job started $(date) as $! done
-
- which causes the shell to monitor all of the jobs started until the script terminates or runs
- out of memory. This would not be a problem if the loop did not reference "$!" or if the script
- would occasionally wait for jobs it started.
-
- FUTURE DIRECTIONS
- None.
-
- SEE ALSO
- Chapter 2, Shell Command Language, kill, sh
-
- The Base Definitions volume of POSIX.1‐2017, Section 3.204, Job Control Job ID, Chapter 8, En‐
- vironment Variables
-
- The System Interfaces volume of POSIX.1‐2017, wait()
-
- COPYRIGHT
- Portions of this text are reprinted and reproduced in electronic form from IEEE Std
- 1003.1-2017, Standard for Information Technology -- Portable Operating System Interface
- (POSIX), The Open Group Base Specifications Issue 7, 2018 Edition, Copyright (C) 2018 by the
- Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of
- any discrepancy between this version and the original IEEE and The Open Group Standard, the
- original IEEE and The Open Group Standard is the referee document. The original Standard can
- be obtained online at http://www.opengroup.org/unix/online.html .
-
- Any typographical or formatting errors that appear in this page are most likely to have been
- introduced during the conversion of the source files to man page format. To report such er‐
- rors, see https://www.kernel.org/doc/man-pages/reporting_bugs.html .
-
- IEEE/The Open Group 2017 WAIT(1POSIX)
wait代码示例04.1 传入参数让子进程延时 全部子进程延时完毕后父进程结束
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
-
- //run model: ./a.out 10 5 15 (three child process, after 10, 5, 15seconds, they are over)
- int main(int argc, char *argv[])
- {
- pid_t child_pid;
- int numDead;
- int i;
-
- for(i = 1; i < argc; i++)
- {
- switch(fork())
- {
- case -1:
- perror("fork()");
- exit(0);
- case 0:
- printf("Child %d started with PID = %d, sleeping %s seconds\n", i, getpid(), argv[i]);
- sleep(atoi(argv[i]));
- exit(0);
- default:
- break;
- }
- }
-
- numDead = 0;
-
- while(1)
- {
- child_pid = wait(NULL);
-
- if(child_pid == -1)
- {
- printf("No more children, Byebye!\n");
- exit(0);
- }
-
- numDead++;
- printf("wait() returned child PID : %d(numDead = %d)\n", child_pid, numDead);
- }
- }
输出
复习下 线程 进程的概念
进程:(动态的概念)(运行着的程序)
创建销毁 耗费资源大
进程间独立
多个进程可以是一个程序
由内核定义 抽象的实体 开辟一系列资源
有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
- PTHREAD_CREATE(3) Linux Programmer's Manual PTHREAD_CREATE(3)
- NAME
- pthread_create - create a new thread
- SYNOPSIS
- #include <pthread.h>
- int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
- void *(*start_routine) (void *), void *arg);
-
- Compile and link with -pthread.
-
- DESCRIPTION
- The pthread_create() function starts a new thread in the calling process. The new thread starts
- execution by invoking start_routine(); arg is passed as the sole argument of start_routine().
- The new thread terminates in one of the following ways:
- * It calls pthread_exit(3), specifying an exit status value that is available to another thread in
- the same process that calls pthread_join(3).
- * It returns from start_routine(). This is equivalent to calling pthread_exit(3) with the value
- supplied in the return statement.
- * It is canceled (see pthread_cancel(3)).
- * Any of the threads in the process calls exit(3), or the main thread performs a return from
- main(). This causes the termination of all threads in the process.
- The attr argument points to a pthread_attr_t structure whose contents are used at thread creation
- time to determine attributes for the new thread; this structure is initialized using
- pthread_attr_init(3) and related functions. If attr is NULL, then the thread is created with de‐
- fault attributes.
- Before returning, a successful call to pthread_create() stores the ID of the new thread in the buf‐
- fer pointed to by thread; this identifier is used to refer to the thread in subsequent calls to
- other pthreads functions.
-
- The new thread inherits a copy of the creating thread's signal mask (pthread_sigmask(3)). The set
- of pending signals for the new thread is empty (sigpending(2)). The new thread does not inherit
- the creating thread's alternate signal stack (sigaltstack(2)).
-
- The new thread inherits the calling thread's floating-point environment (fenv(3)).
-
- The initial value of the new thread's CPU-time clock is 0 (see pthread_getcpuclockid(3)).
-
- Linux-specific details
- The new thread inherits copies of the calling thread's capability sets (see capabilities(7)) and
- CPU affinity mask (see sched_setaffinity(2)).
-
- RETURN VALUE
- On success, pthread_create() returns 0; on error, it returns an error number, and the contents of
- *thread are undefined.
-
- ERRORS
- EAGAIN Insufficient resources to create another thread.
-
- EAGAIN A system-imposed limit on the number of threads was encountered. There are a number of lim‐
- its that may trigger this error: the RLIMIT_NPROC soft resource limit (set via setr‐
- limit(2)), which limits the number of processes and threads for a real user ID, was reached;
- the kernel's system-wide limit on the number of processes and threads, /proc/sys/ker‐
- nel/threads-max, was reached (see proc(5)); or the maximum number of PIDs, /proc/sys/ker‐
- nel/pid_max, was reached (see proc(5)).
- EINVAL Invalid settings in attr.
- EPERM No permission to set the scheduling policy and parameters specified in attr.
- ATTRIBUTES
- For an explanation of the terms used in this section, see attributes(7).
- ┌─────────────────┬───────────────┬─────────┐
- │Interface │ Attribute │ Value │
- ├─────────────────┼───────────────┼─────────┤
- │pthread_create() │ Thread safety │ MT-Safe │
- └─────────────────┴───────────────┴─────────┘
- CONFORMING TO
- POSIX.1-2001, POSIX.1-2008.
- NOTES
- See pthread_self(3) for further information on the thread ID returned in *thread by pthread_cre‐
- ate(). Unless real-time scheduling policies are being employed, after a call to pthread_create(),
- it is indeterminate which thread—the caller or the new thread—will next execute.
- A thread may either be joinable or detached. If a thread is joinable, then another thread can call
- pthread_join(3) to wait for the thread to terminate and fetch its exit status. Only when a termi‐
- nated joinable thread has been joined are the last of its resources released back to the system.
- When a detached thread terminates, its resources are automatically released back to the system: it
- is not possible to join with the thread in order to obtain its exit status. Making a thread de‐
- tached is useful for some types of daemon threads whose exit status the application does not need
- to care about. By default, a new thread is created in a joinable state, unless attr was set to
- create the thread in a detached state (using pthread_attr_setdetachstate(3)).
- Under the NPTL threading implementation, if the RLIMIT_STACK soft resource limit at the time the
- program started has any value other than "unlimited", then it determines the default stack size of
- new threads. Using pthread_attr_setstacksize(3), the stack size attribute can be explicitly set in
- the attr argument used to create a thread, in order to obtain a stack size other than the default.
- If the RLIMIT_STACK resource limit is set to "unlimited", a per-architecture value is used for the
- stack size. Here is the value for a few architectures:
- ┌─────────────┬────────────────────┐
- │Architecture │ Default stack size │
- ├─────────────┼────────────────────┤
- │i386 │ 2 MB │
- ├─────────────┼────────────────────┤
- │IA-64 │ 32 MB │
- ├─────────────┼────────────────────┤
- │PowerPC │ 4 MB │
- ├─────────────┼────────────────────┤
- │S/390 │ 2 MB │
- ├─────────────┼────────────────────┤
- │Sparc-32 │ 2 MB │
- ├─────────────┼────────────────────┤
- │Sparc-64 │ 4 MB │
- ├─────────────┼────────────────────┤
- │x86_64 │ 2 MB │
- └─────────────┴────────────────────┘
- BUGS
- In the obsolete LinuxThreads implementation, each of the threads in a process has a different
- process ID. This is in violation of the POSIX threads specification, and is the source of many
- other nonconformances to the standard; see pthreads(7).
- EXAMPLES
- The program below demonstrates the use of pthread_create(), as well as a number of other functions
- in the pthreads API.
- In the following run, on a system providing the NPTL threading implementation, the stack size de‐
- faults to the value given by the "stack size" resource limit:
- $ ulimit -s
- 8192 # The stack size limit is 8 MB (0x800000 bytes)
- $ ./a.out hola salut servus
- Thread 1: top of stack near 0xb7dd03b8; argv_string=hola
- Thread 2: top of stack near 0xb75cf3b8; argv_string=salut
- Thread 3: top of stack near 0xb6dce3b8; argv_string=servus
- Joined with thread 1; returned value was HOLA
- Joined with thread 2; returned value was SALUT
- Joined with thread 3; returned value was SERVUS
-
- In the next run, the program explicitly sets a stack size of 1 MB (using pthread_attr_setstack‐
- size(3)) for the created threads:
-
- $ ./a.out -s 0x100000 hola salut servus
- Thread 1: top of stack near 0xb7d723b8; argv_string=hola
- Thread 2: top of stack near 0xb7c713b8; argv_string=salut
- Thread 3: top of stack near 0xb7b703b8; argv_string=servus
- Joined with thread 1; returned value was HOLA
- Joined with thread 2; returned value was SALUT
- Joined with thread 3; returned value was SERVUS
-
- Program source
-
- #include <pthread.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <errno.h>
- #include <ctype.h>
-
- #define handle_error_en(en, msg) \
- do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
-
- #define handle_error(msg) \
- do { perror(msg); exit(EXIT_FAILURE); } while (0)
-
- struct thread_info { /* Used as argument to thread_start() */
- pthread_t thread_id; /* ID returned by pthread_create() */
- int thread_num; /* Application-defined thread # */
- char *argv_string; /* From command-line argument */
- };
-
- /* Thread start function: display address near top of our stack,
- and return upper-cased copy of argv_string */
-
- static void *
- thread_start(void *arg)
- {
- struct thread_info *tinfo = arg;
- char *uargv;
-
- printf("Thread %d: top of stack near %p; argv_string=%s\n",
- tinfo->thread_num, &p, tinfo->argv_string);
-
- uargv = strdup(tinfo->argv_string);
- if (uargv == NULL)
- handle_error("strdup");
-
- for (char *p = uargv; *p != '\0'; p++)
- *p = toupper(*p);
-
- return uargv;
- }
-
- int
- main(int argc, char *argv[])
- {
- int s, opt, num_threads;
- pthread_attr_t attr;
- size_t stack_size;
- void *res;
-
- /* The "-s" option specifies a stack size for our threads */
-
- stack_size = -1;
- while ((opt = getopt(argc, argv, "s:")) != -1) {
- switch (opt) {
- case 's':
- stack_size = strtoul(optarg, NULL, 0);
- break;
-
- default:
- fprintf(stderr, "Usage: %s [-s stack-size] arg...\n",
- argv[0]);
- exit(EXIT_FAILURE);
- }
- }
-
- num_threads = argc - optind;
-
- /* Initialize thread creation attributes */
-
- s = pthread_attr_init(&attr);
- if (s != 0)
- handle_error_en(s, "pthread_attr_init");
-
- if (stack_size > 0) {
- s = pthread_attr_setstacksize(&attr, stack_size);
- if (s != 0)
- handle_error_en(s, "pthread_attr_setstacksize");
- }
-
- /* Allocate memory for pthread_create() arguments */
-
- struct thread_info *tinfo = calloc(num_threads, sizeof(*tinfo));
- if (tinfo == NULL)
- handle_error("calloc");
-
- /* Create one thread for each command-line argument */
-
- for (int tnum = 0; tnum < num_threads; tnum++) {
- tinfo[tnum].thread_num = tnum + 1;
- tinfo[tnum].argv_string = argv[optind + tnum];
-
- /* The pthread_create() call stores the thread ID into
- corresponding element of tinfo[] */
-
- s = pthread_create(&tinfo[tnum].thread_id, &attr,
- &thread_start, &tinfo[tnum]);
- if (s != 0)
- handle_error_en(s, "pthread_create");
- }
-
- /* Destroy the thread attributes object, since it is no
- longer needed */
-
- s = pthread_attr_destroy(&attr);
- if (s != 0)
- handle_error_en(s, "pthread_attr_destroy");
-
- /* Now join with each thread, and display its returned value */
-
- for (int tnum = 0; tnum < num_threads; tnum++) {
- s = pthread_join(tinfo[tnum].thread_id, &res);
- if (s != 0)
- handle_error_en(s, "pthread_join");
-
- printf("Joined with thread %d; returned value was %s\n",
- tinfo[tnum].thread_num, (char *) res);
- free(res); /* Free memory allocated by thread */
- }
-
- free(tinfo);
- exit(EXIT_SUCCESS);
- }
-
- SEE ALSO
- getrlimit(2), pthread_attr_init(3), pthread_cancel(3), pthread_detach(3), pthread_equal(3),
- pthread_exit(3), pthread_getattr_np(3), pthread_join(3), pthread_self(3),
- pthread_setattr_default_np(3), pthreads(7)
- COLOPHON
- This page is part of release 5.10 of the Linux man-pages project. A description of the project,
- information about reporting bugs, and the latest version of this page, can be found at
- https://www.kernel.org/doc/man-pages/.
- Linux 2020-11-01 PTHREAD_CREATE(3)
进程等待线程函数 pthread_join
man pthread_join
- PTHREAD_JOIN(3) Linux Programmer's Manual PTHREAD_JOIN(3)
- NAME
- pthread_join - join with a terminated thread
- SYNOPSIS
- #include <pthread.h>
- int pthread_join(pthread_t thread, void **retval);
-
- Compile and link with -pthread.
-
- DESCRIPTION
- The pthread_join() function waits for the thread specified by thread to terminate. If that thread has already
- terminated, then pthread_join() returns immediately. The thread specified by thread must be joinable.
- If retval is not NULL, then pthread_join() copies the exit status of the target thread (i.e., the value that
- the target thread supplied to pthread_exit(3)) into the location pointed to by retval. If the target thread
- was canceled, then PTHREAD_CANCELED is placed in the location pointed to by retval.
- If multiple threads simultaneously try to join with the same thread, the results are undefined. If the thread
- calling pthread_join() is canceled, then the target thread will remain joinable (i.e., it will not be de‐
- tached).
- RETURN VALUE
- On success, pthread_join() returns 0; on error, it returns an error number.
-
- ERRORS
- EDEADLK
- A deadlock was detected (e.g., two threads tried to join with each other); or thread specifies the call‐
- ing thread.
-
- EINVAL thread is not a joinable thread.
-
- EINVAL Another thread is already waiting to join with this thread.
-
- ESRCH No thread with the ID thread could be found.
-
- ATTRIBUTES
- For an explanation of the terms used in this section, see attributes(7).
- ┌───────────────┬───────────────┬─────────┐
- │Interface │ Attribute │ Value │
- ├───────────────┼───────────────┼─────────┤
- │pthread_join() │ Thread safety │ MT-Safe │
- └───────────────┴───────────────┴─────────┘
- CONFORMING TO
- POSIX.1-2001, POSIX.1-2008.
- NOTES
- After a successful call to pthread_join(), the caller is guaranteed that the target thread has terminated. The
- caller may then choose to do any clean-up that is required after termination of the thread (e.g., freeing mem‐
- ory or other resources that were allocated to the target thread).
- Joining with a thread that has previously been joined results in undefined behavior.
- Failure to join with a thread that is joinable (i.e., one that is not detached), produces a "zombie thread".
- Avoid doing this, since each zombie thread consumes some system resources, and when enough zombie threads have
- accumulated, it will no longer be possible to create new threads (or processes).
- There is no pthreads analog of waitpid(-1, &status, 0), that is, "join with any terminated thread". If you be‐
- lieve you need this functionality, you probably need to rethink your application design.
- All of the threads in a process are peers: any thread can join with any other thread in the process.
- EXAMPLES
- See pthread_create(3).
- SEE ALSO
- pthread_cancel(3), pthread_create(3), pthread_detach(3), pthread_exit(3), pthread_tryjoin_np(3), pthreads(7)
- COLOPHON
- This page is part of release 5.10 of the Linux man-pages project. A description of the project, information
- about reporting bugs, and the latest version of this page, can be found at
- https://www.kernel.org/doc/man-pages/.
- Linux 2020-06-09 PTHREAD_JOIN(3)
创建线程代码示例05.1
- #include <pthread.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
-
- void *thread_function(void *arg);
-
- int main(void)
- {
- pthread_t pthread;
- int ret;
- int count = 8;
-
- ret = pthread_create(&pthread, NULL, thread_function, &count);
- if(ret != 0)
- {
- perror("pthread_create");
- exit(1);
- }
-
- pthread_join(pthread, NULL);
- printf("The thread is over, process is over too.\n");
-
- return 0;
- }
-
- void *thread_function(void *arg)
- {
- int i;
- printf("Thread begins running\n");
-
- for(i = 0; i < *(int *)arg; i++)
- {
- printf("Hello world\n");
- sleep(1);
- }
- return NULL;
- }
创建多线程的方法与创建一个线程的方法是一样的
代码示例 06.1
- #include <pthread.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
-
- void *thread1_function(void *arg);
- void *thread2_function(void *arg);
-
- int count = 0;//线程可见
-
- int main(void)
- {
- pthread_t pthread1, pthread2;
- int ret;
-
- ret = pthread_create(&pthread1, NULL, thread1_function, NULL);
- if(ret != 0)
- {
- perror("pthread_create");
- exit(1);
- }
-
- ret = pthread_create(&pthread2, NULL, thread2_function, NULL);
- if(ret != 0)
- {
- perror("pthread_create");
- exit(1);
- }
-
- pthread_join(pthread1, NULL);
- pthread_join(pthread2, NULL);
- printf("The thread is over, process is over too.\n");
-
- return 0;
- }
-
- void *thread1_function(void *arg)
- {
- printf("Thread1 begins running\n");
-
- while(1)
- {
- printf("Thread1 count = %d\n", count++);
- sleep(1);
- }
- return NULL;
- }
-
- void *thread2_function(void *arg)
- {
- printf("Thread2 begins running\n");
- while(1)
- {
- printf("Thread2 count = %d\n", count++);
- sleep(1);
- }
- return NULL;
- }
进程间的通信收手段
管道 pipe
命名管道
无名管道 单向
man pipe
- PIPE(2) Linux Programmer's Manual PIPE(2)
- NAME
- pipe, pipe2 - create pipe
- SYNOPSIS
- #include <unistd.h>
- /* On Alpha, IA-64, MIPS, SuperH, and SPARC/SPARC64; see NOTES */
- struct fd_pair {
- long fd[2];
- };
- struct fd_pair pipe();
-
- /* On all other architectures */
- int pipe(int pipefd[2]);
-
- #define _GNU_SOURCE /* See feature_test_macros(7) */
- #include <fcntl.h> /* Obtain O_* constant definitions */
- #include <unistd.h>
-
- int pipe2(int pipefd[2], int flags);
-
- DESCRIPTION
- pipe() creates a pipe, a unidirectional data channel that can be used for interprocess communication. The ar‐
- ray pipefd is used to return two file descriptors referring to the ends of the pipe. pipefd[0] refers to the
- read end of the pipe. pipefd[1] refers to the write end of the pipe. Data written to the write end of the
- pipe is buffered by the kernel until it is read from the read end of the pipe. For further details, see
- pipe(7).
- If flags is 0, then pipe2() is the same as pipe(). The following values can be bitwise ORed in flags to obtain
- different behavior:
- O_CLOEXEC
- Set the close-on-exec (FD_CLOEXEC) flag on the two new file descriptors. See the description of the
- same flag in open(2) for reasons why this may be useful.
- O_DIRECT (since Linux 3.4)
- Create a pipe that performs I/O in "packet" mode. Each write(2) to the pipe is dealt with as a separate
- packet, and read(2)s from the pipe will read one packet at a time. Note the following points:
- * Writes of greater than PIPE_BUF bytes (see pipe(7)) will be split into multiple packets. The con‐
- stant PIPE_BUF is defined in <limits.h>.
- * If a read(2) specifies a buffer size that is smaller than the next packet, then the requested number
- of bytes are read, and the excess bytes in the packet are discarded. Specifying a buffer size of
- PIPE_BUF will be sufficient to read the largest possible packets (see the previous point).
- * Zero-length packets are not supported. (A read(2) that specifies a buffer size of zero is a no-op,
- and returns 0.)
- Older kernels that do not support this flag will indicate this via an EINVAL error.
- Since Linux 4.5, it is possible to change the O_DIRECT setting of a pipe file descriptor using fcntl(2).
- O_NONBLOCK
- Set the O_NONBLOCK file status flag on the open file descriptions referred to by the new file descrip‐
- tors. Using this flag saves extra calls to fcntl(2) to achieve the same result.
- RETURN VALUE
- On success, zero is returned. On error, -1 is returned, errno is set appropriately, and pipefd is left un‐
- changed.
- On Linux (and other systems), pipe() does not modify pipefd on failure. A requirement standardizing this be‐
- havior was added in POSIX.1-2008 TC2. The Linux-specific pipe2() system call likewise does not modify pipefd
- on failure.
- ERRORS
- EFAULT pipefd is not valid.
- EINVAL (pipe2()) Invalid value in flags.
- EMFILE The per-process limit on the number of open file descriptors has been reached.
- ENFILE The system-wide limit on the total number of open files has been reached.
- ENFILE The user hard limit on memory that can be allocated for pipes has been reached and the caller is not
- privileged; see pipe(7).
- VERSIONS
- pipe2() was added to Linux in version 2.6.27; glibc support is available starting with version 2.9.
-
- CONFORMING TO
- pipe(): POSIX.1-2001, POSIX.1-2008.
- pipe2() is Linux-specific.
- NOTES
- The System V ABI on some architectures allows the use of more than one register for returning multiple values;
- several architectures (namely, Alpha, IA-64, MIPS, SuperH, and SPARC/SPARC64) (ab)use this feature in order to
- implement the pipe() system call in a functional manner: the call doesn't take any arguments and returns a pair
- of file descriptors as the return value on success. The glibc pipe() wrapper function transparently deals with
- this. See syscall(2) for information regarding registers used for storing second file descriptor.
- EXAMPLES
- The following program creates a pipe, and then fork(2)s to create a child process; the child inherits a dupli‐
- cate set of file descriptors that refer to the same pipe. After the fork(2), each process closes the file de‐
- scriptors that it doesn't need for the pipe (see pipe(7)). The parent then writes the string contained in the
- program's command-line argument to the pipe, and the child reads this string a byte at a time from the pipe and
- echoes it on standard output.
- Program source
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- int
- main(int argc, char *argv[])
- {
- int pipefd[2];
- pid_t cpid;
- char buf;
- if (argc != 2) {
- fprintf(stderr, "Usage: %s <string>\n", argv[0]);
- exit(EXIT_FAILURE);
- }
- if (pipe(pipefd) == -1) {
- perror("pipe");
- exit(EXIT_FAILURE);
- }
- cpid = fork();
- if (cpid == -1) {
- perror("fork");
- exit(EXIT_FAILURE);
- }
- if (cpid == 0) { /* Child reads from pipe */
- close(pipefd[1]); /* Close unused write end */
- while (read(pipefd[0], &buf, 1) > 0)
- write(STDOUT_FILENO, &buf, 1);
- write(STDOUT_FILENO, "\n", 1);
- close(pipefd[0]);
- _exit(EXIT_SUCCESS);
- } else { /* Parent writes argv[1] to pipe */
- close(pipefd[0]); /* Close unused read end */
- write(pipefd[1], argv[1], strlen(argv[1]));
- close(pipefd[1]); /* Reader will see EOF */
- wait(NULL); /* Wait for child */
- exit(EXIT_SUCCESS);
- }
- }
- SEE ALSO
- fork(2), read(2), socketpair(2), splice(2), tee(2), vmsplice(2), write(2), popen(3), pipe(7)
- COLOPHON
- This page is part of release 5.10 of the Linux man-pages project. A description of the project, information
- about reporting bugs, and the latest version of this page, can be found at
- https://www.kernel.org/doc/man-pages/.
- Linux 2020-06-09 PIPE(2)
现实现 利用管道 父进程向子进程写入数据。
代码示例07.1
- /*
- parent process: write pipe
- child process: read pipe
- */
- #include <unistd.h>
- #include <sys/types.h>
- #include <stdio.h>
-
- int main(void)
- {
- int fd[2];
- int pid;
-
- if(pipe(fd) == -1)
- perror("pipe");
-
- pid = fork();
- if(pid > 0) //parent process
- {
- close(fd[0]);
- sleep(5);
- write(fd[1], "ab", 2);
-
- while(1);
- }
- else if(pid == 0)
- {
- char ch[2];
-
- printf("Child process is waiting for data: \n");
- close(fd[1]);
- read(fd[0], ch, 2);//没有写入 阻塞等待
- printf("Read from pipe: %s\n", ch);
- }
-
- return 0;
- }
向管道循环注入数据测试管道能够装载的最大值
代码示例08.1.c
- #include <unistd.h>
- #include <sys/types.h>
- #include <stdio.h>
- #include <sys/wait.h>
-
- int main(void)
- {
- pid_t pid;
- int fd[2];
-
- if(pipe(fd) == -1)
- perror("pipe");
-
- pid = fork();
-
- if(pid == 0) //child process: write to the pipe
- {
- char ch = '*';
- int n = 0;
-
- close(fd[0]);
-
- while(1)
- {
- write(fd[1], &ch, 1);
- printf("count = %d\n", ++n);
- }
- }
- else if(pid > 0) //parent process: wait until child process is over
- {
- waitpid(pid, NULL, 0);
- }
- }
父进程等待之进程的输入。
代码示例09.1.c
- #include <unistd.h>
- #include <sys/types.h>
- #include <stdio.h>
- #include <sys/wait.h>
-
- int main(void)
- {
- pid_t pid;
- int fd[2];
-
- if(pipe(fd) == -1)
- perror("pipe");
-
- pid = fork();
-
- if(pid == 0)
- {
- char tmp[100];
-
- close(fd[0]);
-
- while(1)
- {
- scanf("%s", tmp);
- write(fd[1], tmp, sizeof(tmp));
- }
- }
- else if(pid > 0)
- {
- char tmp[100];
- close(fd[1]);
-
- while(1)
- {
- printf("Parent process is waiting for the data from pipe:\n");
- read(fd[0], tmp, sizeof(tmp));
- printf("read from pipe: %s\n", tmp);
- }
- }
-
- return 0;
- }
父进程实现小写转换大写传回子进程输出。
代码示例10.1.c
- #include <unistd.h>
- #include <sys/types.h>
- #include <stdio.h>
- #include <sys/wait.h>
- #include <string.h>
- #include <ctype.h>
-
- int main(void)
- {
- pid_t pid;
- int fd[2];
- int fd2[2];
-
- if(pipe(fd) == -1)
- perror("pipe");
- if(pipe(fd2) == -1)
- perror("pipe");
-
- pid = fork();
-
- if(pid == 0)
- {
- char tmp[100];
- int i;
-
- close(fd[1]);
- close(fd2[0]);
-
- while(1)
- {
- memset(tmp, '\0', sizeof(tmp));
- read(fd[0], tmp, sizeof(tmp));
-
- for(i = 0; i < sizeof(tmp); i++)
- tmp[i] = toupper(tmp[i]);
-
- write(fd2[1], tmp, sizeof(tmp));
- }
- }
- else if(pid > 0)
- {
- char tmp[100];
- close(fd[0]);
- close(fd2[1]);
-
- while(1)
- {
- memset(tmp, '\0', sizeof(tmp));
- gets(tmp);
- write(fd[1], tmp, sizeof(tmp));
-
- memset(tmp, '\0', sizeof(tmp));
- read(fd2[0], tmp, sizeof(tmp));
- printf("After change: %s\n", tmp);
- }
- }
-
- return 0;
- }
概念引出
无名管道只适用于有亲缘关系的进程间。
没有亲缘关系的两个进程是否可以进行通信 ?
查看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]
- MKFIFO(3) Linux Programmer's Manual MKFIFO(3)
- NAME
- mkfifo, mkfifoat - make a FIFO special file (a named pipe)
- SYNOPSIS
- #include <sys/types.h>
- #include <sys/stat.h>
- int mkfifo(const char *pathname, mode_t mode);
-
- #include <fcntl.h> /* Definition of AT_* constants */
- #include <sys/stat.h>
-
- int mkfifoat(int dirfd, const char *pathname, mode_t mode);
-
- Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
- mkfifoat():
- Since glibc 2.10:
- _POSIX_C_SOURCE >= 200809L
- Before glibc 2.10:
- _ATFILE_SOURCE
- DESCRIPTION
- mkfifo() makes a FIFO special file with name pathname. mode specifies the
- FIFO's permissions. It is modified by the process's umask in the usual
- way: the permissions of the created file are (mode & ~umask).
- A FIFO special file is similar to a pipe, except that it is created in a
- different way. Instead of being an anonymous communications channel, a
- FIFO special file is entered into the filesystem by calling mkfifo().
- Once you have created a FIFO special file in this way, any process can
- open it for reading or writing, in the same way as an ordinary file. How‐
- ever, it has to be open at both ends simultaneously before you can proceed
- to do any input or output operations on it. Opening a FIFO for reading
- normally blocks until some other process opens the same FIFO for writing,
- and vice versa. See fifo(7) for nonblocking handling of FIFO special
- files.
- mkfifoat()
- The mkfifoat() function operates in exactly the same way as mkfifo(), ex‐
- cept for the differences described here.
- If the pathname given in pathname is relative, then it is interpreted rel‐
- ative to the directory referred to by the file descriptor dirfd (rather
- than relative to the current working directory of the calling process, as
- is done by mkfifo() for a relative pathname).
- If pathname is relative and dirfd is the special value AT_FDCWD, then
- pathname is interpreted relative to the current working directory of the
- calling process (like mkfifo()).
- If pathname is absolute, then dirfd is ignored.
- RETURN VALUE
- On success mkfifo() and mkfifoat() return 0. In the case of an error, -1
- is returned (in which case, errno is set appropriately).
- ERRORS
- EACCES One of the directories in pathname did not allow search (execute)
- permission.
- EDQUOT The user's quota of disk blocks or inodes on the filesystem has
- been exhausted.
- EEXIST pathname already exists. This includes the case where pathname is
- a symbolic link, dangling or not.
- ENAMETOOLONG
- Either the total length of pathname is greater than PATH_MAX, or an
- individual filename component has a length greater than NAME_MAX.
- In the GNU system, there is no imposed limit on overall filename
- length, but some filesystems may place limits on the length of a
- component.
- ENOENT A directory component in pathname does not exist or is a dangling
- symbolic link.
- ENOSPC The directory or filesystem has no room for the new file.
- ENOTDIR
- A component used as a directory in pathname is not, in fact, a di‐
- rectory.
- EROFS pathname refers to a read-only filesystem.
- The following additional errors can occur for mkfifoat():
- EBADF dirfd is not a valid file descriptor.
- ENOTDIR
- pathname is a relative path and dirfd is a file descriptor refer‐
- ring to a file other than a directory.
- VERSIONS
- mkfifoat() was added to glibc in version 2.4. It is implemented using
- mknodat(2), available on Linux since kernel 2.6.16.
- ATTRIBUTES
- For an explanation of the terms used in this section, see attributes(7).
- ┌─────────────────────┬───────────────┬─────────┐
- │Interface │ Attribute │ Value │
- ├─────────────────────┼───────────────┼─────────┤
- │mkfifo(), mkfifoat() │ Thread safety │ MT-Safe │
- └─────────────────────┴───────────────┴─────────┘
- CONFORMING TO
- mkfifo(): POSIX.1-2001, POSIX.1-2008.
- mkfifoat(): POSIX.1-2008.
- SEE ALSO
- mkfifo(1), close(2), open(2), read(2), stat(2), umask(2), write(2),
- fifo(7)
- COLOPHON
- This page is part of release 5.10 of the Linux man-pages project. A de‐
- scription of the project, information about reporting bugs, and the latest
- version of this page, can be found at
- https://www.kernel.org/doc/man-pages/.
- GNU 2020-08-13 MKFIFO(3)
代码示例11.1.c 创建有名管道 一直向管道读取
- #include <stdio.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <string.h>
-
- int main(void)
- {
- int ret;
- int fd;
- char buf[100];
-
- ret = mkfifo("my_fifo", 0666);
- if(ret != 0)
- perror("mkfifo");
-
- printf("Prepare reading from named pipe:\n");
-
- fd = open("my_fifo", O_RDWR);
- if(fd == -1)
- perror("open");
-
- while(1)
- {
- memset(buf, '\0', sizeof(buf));
- read(fd, buf, sizeof(buf));
- printf("Read from named pipe: %s\n", buf);
- sleep(1);
- }
-
- return 0;
- }
代码示例11.2.c 用户交互 向管道写入数据
- #include <stdio.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <string.h>
- #include <stdlib.h>
-
- int main(int argc, char *argv[])
- {
- int fd;
- char buf[100];
-
- fd = open("my_fifo", O_WRONLY);
- if(fd == -1)
- perror("open");
-
- if(argc == 1)
- {
- printf("Please send something to the named pipe:\n");
- exit(EXIT_FAILURE);
- }
-
- strcpy(buf, argv[1]);
- write(fd, buf, sizeof(buf));
- printf("Write to the pipe: %s\n", buf);
-
- return 0;
- }
man shmget
- SHMGET(2) Linux Programmer's Manual SHMGET(2)
- NAME
- shmget - allocates a System V shared memory segment
- SYNOPSIS
- #include <sys/ipc.h>
- #include <sys/shm.h>
- int shmget(key_t key, size_t size, int shmflg);
-
- DESCRIPTION
- shmget() returns the identifier of the System V shared memory segment associated with the value of the argument key. It may be used ei‐
- 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‐
- VATE), or to create a new set.
- 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
- IPC_PRIVATE or key isn't IPC_PRIVATE, no shared memory segment corresponding to key exists, and IPC_CREAT is specified in shmflg.
- 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
- EEXIST. (This is analogous to the effect of the combination O_CREAT | O_EXCL for open(2).)
- The value shmflg is composed of:
- IPC_CREAT
- 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
- user has permission to access the segment.
- IPC_EXCL
- This flag is used with IPC_CREAT to ensure that this call creates the segment. If the segment already exists, the call fails.
- SHM_HUGETLB (since Linux 2.6)
- Allocate the segment using "huge pages." See the Linux kernel source file Documentation/admin-guide/mm/hugetlbpage.rst for fur‐
- ther information.
- SHM_HUGE_2MB, SHM_HUGE_1GB (since Linux 3.8)
- Used in conjunction with SHM_HUGETLB to select alternative hugetlb page sizes (respectively, 2 MB and 1 GB) on systems that sup‐
- port multiple hugetlb page sizes.
- More generally, the desired huge page size can be configured by encoding the base-2 logarithm of the desired page size in the six
- bits at the offset SHM_HUGE_SHIFT. Thus, the above two constants are defined as:
- #define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT)
- #define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT)
- For some additional details, see the discussion of the similarly named constants in mmap(2).
- SHM_NORESERVE (since Linux 2.6.15)
- This flag serves the same purpose as the mmap(2) MAP_NORESERVE flag. Do not reserve swap space for this segment. When swap space
- is reserved, one has the guarantee that it is possible to modify the segment. When swap space is not reserved one might get
- SIGSEGV upon a write if no physical memory is available. See also the discussion of the file /proc/sys/vm/overcommit_memory in
- proc(5).
- In addition to the above flags, the least significant 9 bits of shmflg specify the permissions granted to the owner, group, and others.
- These bits have the same format, and the same meaning, as the mode argument of open(2). Presently, execute permissions are not used by
- the system.
- When a new shared memory segment is created, its contents are initialized to zero values, and its associated data structure, shmid_ds
- (see shmctl(2)), is initialized as follows:
- • shm_perm.cuid and shm_perm.uid are set to the effective user ID of the calling process.
- • shm_perm.cgid and shm_perm.gid are set to the effective group ID of the calling process.
- • The least significant 9 bits of shm_perm.mode are set to the least significant 9 bit of shmflg.
- • shm_segsz is set to the value of size.
- • shm_lpid, shm_nattch, shm_atime, and shm_dtime are set to 0.
- • shm_ctime is set to the current time.
- If the shared memory segment already exists, the permissions are verified, and a check is made to see if it is marked for destruction.
- RETURN VALUE
- On success, a valid shared memory identifier is returned. On error, -1 is returned, and errno is set to indicate the error.
- ERRORS
- On failure, errno is set to one of the following:
- 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
- namespace that governs its IPC namespace.
- EEXIST IPC_CREAT and IPC_EXCL were specified in shmflg, but a shared memory segment already exists for key.
- EINVAL A new segment was to be created and size is less than SHMMIN or greater than SHMMAX.
- EINVAL A segment for the given key exists, but size is greater than the size of that segment.
- ENFILE The system-wide limit on the total number of open files has been reached.
- ENOENT No segment exists for the given key, and IPC_CREAT was not specified.
- ENOMEM No memory could be allocated for segment overhead.
- ENOSPC All possible shared memory IDs have been taken (SHMMNI), or allocating a segment of the requested size would cause the system to
- exceed the system-wide limit on shared memory (SHMALL).
- EPERM The SHM_HUGETLB flag was specified, but the caller was not privileged (did not have the CAP_IPC_LOCK capability).
- CONFORMING TO
- POSIX.1-2001, POSIX.1-2008, SVr4.
- SHM_HUGETLB and SHM_NORESERVE are Linux extensions.
- NOTES
- 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‐
- quired the inclusion of these header files, and the SVID also documented their inclusion. Applications intended to be portable to such
- old systems may need to include these header files.
- 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‐
- nificant 9 bits of shmflg and creates a new shared memory segment.
- Shared memory limits
- The following limits on shared memory segment resources affect the shmget() call:
- SHMALL System-wide limit on the total amount of shared memory, measured in units of the system page size.
- 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:
- ULONG_MAX - 2^24
- The effect of this value (which is suitable for both 32-bit and 64-bit systems) is to impose no limitation on allocations. This
- value, rather than ULONG_MAX, was chosen as the default to prevent some cases where historical applications simply raised the ex‐
- isting limit without first checking its current value. Such applications would cause the value to overflow if the limit was set
- at ULONG_MAX.
- From Linux 2.4 up to Linux 3.15, the default value for this limit was:
- SHMMAX / PAGE_SIZE * (SHMMNI / 16)
- If SHMMAX and SHMMNI were not modified, then multiplying the result of this formula by the page size (to get a value in bytes)
- yielded a value of 8 GB as the limit on the total memory used by all shared memory segments.
- SHMMAX Maximum size in bytes for a shared memory segment.
- 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:
- ULONG_MAX - 2^24
- The effect of this value (which is suitable for both 32-bit and 64-bit systems) is to impose no limitation on allocations. See
- the description of SHMALL for a discussion of why this default value (rather than ULONG_MAX) is used.
- From Linux 2.2 up to Linux 3.15, the default value of this limit was 0x2000000 (32 MB).
- Because it is not possible to map just part of a shared memory segment, the amount of virtual memory places another limit on the
- 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
- on x86-64 the limit is around 127 TB.
- SHMMIN Minimum size in bytes for a shared memory segment: implementation dependent (currently 1 byte, though PAGE_SIZE is the effective
- minimum size).
- 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
- 2.4, the default value is 4096.
-
- On Linux, this limit can be read and modified via /proc/sys/kernel/shmmni.
-
- The implementation has no specific limits for the per-process maximum number of shared memory segments (SHMSEG).
- Linux notes
- Until version 2.3.30, Linux would return EIDRM for a shmget() on a shared memory segment scheduled for deletion.
- BUGS
- The name choice IPC_PRIVATE was perhaps unfortunate, IPC_NEW would more clearly show its function.
- EXAMPLES
- See shmop(2).
- SEE ALSO
- memfd_create(2), shmat(2), shmctl(2), shmdt(2), ftok(3), capabilities(7), shm_overview(7), sysvipc(7)
- COLOPHON
- This page is part of release 5.10 of the Linux man-pages project. A description of the project, information about reporting bugs, and
- the latest version of this page, can be found at https://www.kernel.org/doc/man-pages/.
- Linux 2020-04-11 SHMGET(2)
man shmdt
- SHMOP(2) Linux Programmer's Manual SHMOP(2)
- NAME
- shmat, shmdt - System V shared memory operations
- SYNOPSIS
- #include <sys/types.h>
- #include <sys/shm.h>
- void *shmat(int shmid, const void *shmaddr, int shmflg);
-
- int shmdt(const void *shmaddr);
-
- DESCRIPTION
- shmat()
- shmat() attaches the System V shared memory segment identified by shmid to the address space of the calling process. The attaching ad‐
- dress is specified by shmaddr with one of the following criteria:
- • If shmaddr is NULL, the system chooses a suitable (unused) page-aligned address to attach the segment.
- • 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
- multiple of SHMLBA.
- • Otherwise, shmaddr must be a page-aligned address at which the attach occurs.
- In addition to SHM_RND, the following flags may be specified in the shmflg bit-mask argument:
- SHM_EXEC (Linux-specific; since Linux 2.6.9)
- Allow the contents of the segment to be executed. The caller must have execute permission on the segment.
- SHM_RDONLY
- Attach the segment for read-only access. The process must have read permission for the segment. If this flag is not specified,
- the segment is attached for read and write access, and the process must have read and write permission for the segment. There is
- no notion of a write-only shared memory segment.
- SHM_REMAP (Linux-specific)
- This flag specifies that the mapping of the segment should replace any existing mapping in the range starting at shmaddr and con‐
- tinuing for the size of the segment. (Normally, an EINVAL error would result if a mapping already exists in this address range.)
- In this case, shmaddr must not be NULL.
- The brk(2) value of the calling process is not altered by the attach. The segment will automatically be detached at process exit. The
- same segment may be attached as a read and as a read-write one, and more than once, in the process's address space.
- A successful shmat() call updates the members of the shmid_ds structure (see shmctl(2)) associated with the shared memory segment as fol‐
- lows:
- • shm_atime is set to the current time.
- • shm_lpid is set to the process-ID of the calling process.
- • shm_nattch is incremented by one.
- shmdt()
- shmdt() detaches the shared memory segment located at the address specified by shmaddr from the address space of the calling process.
- The to-be-detached segment must be currently attached with shmaddr equal to the value returned by the attaching shmat() call.
- On a successful shmdt() call, the system updates the members of the shmid_ds structure associated with the shared memory segment as fol‐
- lows:
- • shm_dtime is set to the current time.
- • shm_lpid is set to the process-ID of the calling process.
- • shm_nattch is decremented by one. If it becomes 0 and the segment is marked for deletion, the segment is deleted.
- RETURN VALUE
- On success, shmat() returns the address of the attached shared memory segment; on error, (void *) -1 is returned, and errno is set to in‐
- dicate the cause of the error.
-
- On success, shmdt() returns 0; on error -1 is returned, and errno is set to indicate the cause of the error.
-
- ERRORS
- When shmat() fails, errno is set to one of the following:
- EACCES The calling process does not have the required permissions for the requested attach type, and does not have the CAP_IPC_OWNER ca‐
- pability in the user namespace that governs its IPC namespace.
- EIDRM shmid points to a removed identifier.
- EINVAL Invalid shmid value, unaligned (i.e., not page-aligned and SHM_RND was not specified) or invalid shmaddr value, or can't attach
- segment at shmaddr, or SHM_REMAP was specified and shmaddr was NULL.
- ENOMEM Could not allocate memory for the descriptor or for the page tables.
- When shmdt() fails, errno is set as follows:
- EINVAL There is no shared memory segment attached at shmaddr; or, shmaddr is not aligned on a page boundary.
- CONFORMING TO
- POSIX.1-2001, POSIX.1-2008, SVr4.
- In SVID 3 (or perhaps earlier), the type of the shmaddr argument was changed from char * into const void *, and the returned type of
- shmat() from char * into void *.
- NOTES
- After a fork(2), the child inherits the attached shared memory segments.
- After an execve(2), all attached shared memory segments are detached from the process.
- Upon _exit(2), all attached shared memory segments are detached from the process.
- Using shmat() with shmaddr equal to NULL is the preferred, portable way of attaching a shared memory segment. Be aware that the shared
- memory segment attached in this way may be attached at different addresses in different processes. Therefore, any pointers maintained
- within the shared memory must be made relative (typically to the starting address of the segment), rather than absolute.
- 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
- this behavior and many other implementations do not support it.
- The following system parameter affects shmat():
- SHMLBA Segment low boundary address multiple. When explicitly specifying an attach address in a call to shmat(), the caller should en‐
- sure that the address is a multiple of this value. This is necessary on some architectures, in order either to ensure good CPU
- cache performance or to ensure that different attaches of the same segment have consistent views within the CPU cache. SHMLBA is
- normally some multiple of the system page size. (On many Linux architectures, SHMLBA is the same as the system page size.)
- The implementation places no intrinsic per-process limit on the number of shared memory segments (SHMSEG).
- EXAMPLES
- The two programs shown below exchange a string using a shared memory segment. Further details about the programs are given below.
- First, we show a shell session demonstrating their use.
- In one terminal window, we run the "reader" program, which creates a System V shared memory segment and a System V semaphore set. The
- program prints out the IDs of the created objects, and then waits for the semaphore to change value.
- $ ./svshm_string_read
- shmid = 1114194; semid = 15
- In another terminal window, we run the "writer" program. The "writer" program takes three command-line arguments: the IDs of the shared
- memory segment and semaphore set created by the "reader", and a string. It attaches the existing shared memory segment, copies the
- string to the shared memory, and modifies the semaphore value.
- $ ./svshm_string_write 1114194 15 'Hello, world'
- Returning to the terminal where the "reader" is running, we see that the program has ceased waiting on the semaphore and has printed the
- string that was copied into the shared memory segment by the writer:
- Hello, world
- Program source: svshm_string.h
- The following header file is included by the "reader" and "writer" programs.
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/sem.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
- } while (0)
-
- union semun { /* Used in calls to semctl() */
- int val;
- struct semid_ds * buf;
- unsigned short * array;
- #if defined(__linux__)
- struct seminfo * __buf;
- #endif
- };
-
- #define MEM_SIZE 4096
-
- Program source: svshm_string_read.c
- The "reader" program creates a shared memory segment and a semaphore set containing one semaphore. It then attaches the shared memory
- object into its address space and initializes the semaphore value to 1. Finally, the program waits for the semaphore value to become 0,
- and afterwards prints the string that has been copied into the shared memory segment by the "writer".
-
- /* svshm_string_read.c
- Licensed under GNU General Public License v2 or later.
- */
- #include "svshm_string.h"
-
- int
- main(int argc, char *argv[])
- {
- int semid, shmid;
- union semun arg, dummy;
- struct sembuf sop;
- char *addr;
-
- /* Create shared memory and semaphore set containing one
- semaphore */
-
- shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600);
- if (shmid == -1)
- errExit("shmget");
-
- semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
- if (shmid == -1)
- errExit("shmget");
-
- /* Attach shared memory into our address space */
-
- addr = shmat(shmid, NULL, SHM_RDONLY);
- if (addr == (void *) -1)
- errExit("shmat");
-
- /* Initialize semaphore 0 in set with value 1 */
-
- arg.val = 1;
- if (semctl(semid, 0, SETVAL, arg) == -1)
- errExit("semctl");
-
- printf("shmid = %d; semid = %d\n", shmid, semid);
-
- /* Wait for semaphore value to become 0 */
-
- sop.sem_num = 0;
- sop.sem_op = 0;
- sop.sem_flg = 0;
-
- if (semop(semid, &sop, 1) == -1)
- errExit("semop");
-
- /* Print the string from shared memory */
-
- printf("%s\n", addr);
-
- /* Remove shared memory and semaphore set */
-
- if (shmctl(shmid, IPC_RMID, NULL) == -1)
- errExit("shmctl");
- if (semctl(semid, 0, IPC_RMID, dummy) == -1)
- errExit("semctl");
-
- exit(EXIT_SUCCESS);
- }
-
- Program source: svshm_string_write.c
- The writer program takes three command-line arguments: the IDs of the shared memory segment and semaphore set that have already been cre‐
- ated by the "reader", and a string. It attaches the shared memory segment into its address space, and then decrements the semaphore
- value to 0 in order to inform the "reader" that it can now examine the contents of the shared memory.
-
- /* svshm_string_write.c
- Licensed under GNU General Public License v2 or later.
- */
- #include "svshm_string.h"
-
- int
- main(int argc, char *argv[])
- {
- int semid, shmid;
- struct sembuf sop;
- char *addr;
- size_t len;
-
- if (argc != 4) {
- fprintf(stderr, "Usage: %s shmid semid string\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- len = strlen(argv[3]) + 1; /* +1 to include trailing '\0' */
- if (len > MEM_SIZE) {
- fprintf(stderr, "String is too big!\n");
- exit(EXIT_FAILURE);
- }
-
- /* Get object IDs from command-line */
-
- shmid = atoi(argv[1]);
- semid = atoi(argv[2]);
-
- /* Attach shared memory into our address space and copy string
- (including trailing null byte) into memory. */
-
- addr = shmat(shmid, NULL, 0);
- if (addr == (void *) -1)
- errExit("shmat");
-
- memcpy(addr, argv[3], len);
-
- /* Decrement semaphore to 0 */
-
- sop.sem_num = 0;
- sop.sem_op = -1;
- sop.sem_flg = 0;
-
- if (semop(semid, &sop, 1) == -1)
- errExit("semop");
-
- exit(EXIT_SUCCESS);
- }
-
- SEE ALSO
- brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), sysvipc(7)
- COLOPHON
- This page is part of release 5.10 of the Linux man-pages project. A description of the project, information about reporting bugs, and
- the latest version of this page, can be found at https://www.kernel.org/doc/man-pages/.
- Linux 2020-04-11 SHMOP(2)
man shmat
- SHMOP(2) Linux Programmer's Manual SHMOP(2)
- NAME
- shmat, shmdt - System V shared memory operations
- SYNOPSIS
- #include <sys/types.h>
- #include <sys/shm.h>
- void *shmat(int shmid, const void *shmaddr, int shmflg);
-
- int shmdt(const void *shmaddr);
-
- DESCRIPTION
- shmat()
- shmat() attaches the System V shared memory segment identified by shmid to the address space of the calling process. The attaching ad‐
- dress is specified by shmaddr with one of the following criteria:
- • If shmaddr is NULL, the system chooses a suitable (unused) page-aligned address to attach the segment.
- • 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
- multiple of SHMLBA.
- • Otherwise, shmaddr must be a page-aligned address at which the attach occurs.
- In addition to SHM_RND, the following flags may be specified in the shmflg bit-mask argument:
- SHM_EXEC (Linux-specific; since Linux 2.6.9)
- Allow the contents of the segment to be executed. The caller must have execute permission on the segment.
- SHM_RDONLY
- Attach the segment for read-only access. The process must have read permission for the segment. If this flag is not specified,
- the segment is attached for read and write access, and the process must have read and write permission for the segment. There is
- no notion of a write-only shared memory segment.
- SHM_REMAP (Linux-specific)
- This flag specifies that the mapping of the segment should replace any existing mapping in the range starting at shmaddr and con‐
- tinuing for the size of the segment. (Normally, an EINVAL error would result if a mapping already exists in this address range.)
- In this case, shmaddr must not be NULL.
- The brk(2) value of the calling process is not altered by the attach. The segment will automatically be detached at process exit. The
- same segment may be attached as a read and as a read-write one, and more than once, in the process's address space.
- A successful shmat() call updates the members of the shmid_ds structure (see shmctl(2)) associated with the shared memory segment as fol‐
- lows:
- • shm_atime is set to the current time.
- • shm_lpid is set to the process-ID of the calling process.
- • shm_nattch is incremented by one.
- shmdt()
- shmdt() detaches the shared memory segment located at the address specified by shmaddr from the address space of the calling process.
- The to-be-detached segment must be currently attached with shmaddr equal to the value returned by the attaching shmat() call.
- On a successful shmdt() call, the system updates the members of the shmid_ds structure associated with the shared memory segment as fol‐
- lows:
- • shm_dtime is set to the current time.
- • shm_lpid is set to the process-ID of the calling process.
- • shm_nattch is decremented by one. If it becomes 0 and the segment is marked for deletion, the segment is deleted.
- RETURN VALUE
- On success, shmat() returns the address of the attached shared memory segment; on error, (void *) -1 is returned, and errno is set to in‐
- dicate the cause of the error.
-
- On success, shmdt() returns 0; on error -1 is returned, and errno is set to indicate the cause of the error.
-
- ERRORS
- When shmat() fails, errno is set to one of the following:
- EACCES The calling process does not have the required permissions for the requested attach type, and does not have the CAP_IPC_OWNER ca‐
- pability in the user namespace that governs its IPC namespace.
- EIDRM shmid points to a removed identifier.
- EINVAL Invalid shmid value, unaligned (i.e., not page-aligned and SHM_RND was not specified) or invalid shmaddr value, or can't attach
- segment at shmaddr, or SHM_REMAP was specified and shmaddr was NULL.
- ENOMEM Could not allocate memory for the descriptor or for the page tables.
- When shmdt() fails, errno is set as follows:
- EINVAL There is no shared memory segment attached at shmaddr; or, shmaddr is not aligned on a page boundary.
- CONFORMING TO
- POSIX.1-2001, POSIX.1-2008, SVr4.
- In SVID 3 (or perhaps earlier), the type of the shmaddr argument was changed from char * into const void *, and the returned type of
- shmat() from char * into void *.
- NOTES
- After a fork(2), the child inherits the attached shared memory segments.
- After an execve(2), all attached shared memory segments are detached from the process.
- Upon _exit(2), all attached shared memory segments are detached from the process.
- Using shmat() with shmaddr equal to NULL is the preferred, portable way of attaching a shared memory segment. Be aware that the shared
- memory segment attached in this way may be attached at different addresses in different processes. Therefore, any pointers maintained
- within the shared memory must be made relative (typically to the starting address of the segment), rather than absolute.
- 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
- this behavior and many other implementations do not support it.
- The following system parameter affects shmat():
- SHMLBA Segment low boundary address multiple. When explicitly specifying an attach address in a call to shmat(), the caller should en‐
- sure that the address is a multiple of this value. This is necessary on some architectures, in order either to ensure good CPU
- cache performance or to ensure that different attaches of the same segment have consistent views within the CPU cache. SHMLBA is
- normally some multiple of the system page size. (On many Linux architectures, SHMLBA is the same as the system page size.)
- The implementation places no intrinsic per-process limit on the number of shared memory segments (SHMSEG).
- EXAMPLES
- The two programs shown below exchange a string using a shared memory segment. Further details about the programs are given below.
- First, we show a shell session demonstrating their use.
- In one terminal window, we run the "reader" program, which creates a System V shared memory segment and a System V semaphore set. The
- program prints out the IDs of the created objects, and then waits for the semaphore to change value.
- $ ./svshm_string_read
- shmid = 1114194; semid = 15
- In another terminal window, we run the "writer" program. The "writer" program takes three command-line arguments: the IDs of the shared
- memory segment and semaphore set created by the "reader", and a string. It attaches the existing shared memory segment, copies the
- string to the shared memory, and modifies the semaphore value.
- $ ./svshm_string_write 1114194 15 'Hello, world'
- Returning to the terminal where the "reader" is running, we see that the program has ceased waiting on the semaphore and has printed the
- string that was copied into the shared memory segment by the writer:
- Hello, world
- Program source: svshm_string.h
- The following header file is included by the "reader" and "writer" programs.
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/sem.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
- } while (0)
-
- union semun { /* Used in calls to semctl() */
- int val;
- struct semid_ds * buf;
- unsigned short * array;
- #if defined(__linux__)
- struct seminfo * __buf;
- #endif
- };
-
- #define MEM_SIZE 4096
-
- Program source: svshm_string_read.c
- The "reader" program creates a shared memory segment and a semaphore set containing one semaphore. It then attaches the shared memory
- object into its address space and initializes the semaphore value to 1. Finally, the program waits for the semaphore value to become 0,
- and afterwards prints the string that has been copied into the shared memory segment by the "writer".
-
- /* svshm_string_read.c
- Licensed under GNU General Public License v2 or later.
- */
- #include "svshm_string.h"
-
- int
- main(int argc, char *argv[])
- {
- int semid, shmid;
- union semun arg, dummy;
- struct sembuf sop;
- char *addr;
-
- /* Create shared memory and semaphore set containing one
- semaphore */
-
- shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600);
- if (shmid == -1)
- errExit("shmget");
-
- semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
- if (shmid == -1)
- errExit("shmget");
-
- /* Attach shared memory into our address space */
-
- addr = shmat(shmid, NULL, SHM_RDONLY);
- if (addr == (void *) -1)
- errExit("shmat");
-
- /* Initialize semaphore 0 in set with value 1 */
-
- arg.val = 1;
- if (semctl(semid, 0, SETVAL, arg) == -1)
- errExit("semctl");
-
- printf("shmid = %d; semid = %d\n", shmid, semid);
-
- /* Wait for semaphore value to become 0 */
-
- sop.sem_num = 0;
- sop.sem_op = 0;
- sop.sem_flg = 0;
-
- if (semop(semid, &sop, 1) == -1)
- errExit("semop");
-
- /* Print the string from shared memory */
-
- printf("%s\n", addr);
-
- /* Remove shared memory and semaphore set */
-
- if (shmctl(shmid, IPC_RMID, NULL) == -1)
- errExit("shmctl");
- if (semctl(semid, 0, IPC_RMID, dummy) == -1)
- errExit("semctl");
-
- exit(EXIT_SUCCESS);
- }
-
- Program source: svshm_string_write.c
- The writer program takes three command-line arguments: the IDs of the shared memory segment and semaphore set that have already been cre‐
- ated by the "reader", and a string. It attaches the shared memory segment into its address space, and then decrements the semaphore
- value to 0 in order to inform the "reader" that it can now examine the contents of the shared memory.
-
- /* svshm_string_write.c
- Licensed under GNU General Public License v2 or later.
- */
- #include "svshm_string.h"
-
- int
- main(int argc, char *argv[])
- {
- int semid, shmid;
- struct sembuf sop;
- char *addr;
- size_t len;
-
- if (argc != 4) {
- fprintf(stderr, "Usage: %s shmid semid string\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- len = strlen(argv[3]) + 1; /* +1 to include trailing '\0' */
- if (len > MEM_SIZE) {
- fprintf(stderr, "String is too big!\n");
- exit(EXIT_FAILURE);
- }
-
- /* Get object IDs from command-line */
-
- shmid = atoi(argv[1]);
- semid = atoi(argv[2]);
-
- /* Attach shared memory into our address space and copy string
- (including trailing null byte) into memory. */
-
- addr = shmat(shmid, NULL, 0);
- if (addr == (void *) -1)
- errExit("shmat");
-
- memcpy(addr, argv[3], len);
-
- /* Decrement semaphore to 0 */
-
- sop.sem_num = 0;
- sop.sem_op = -1;
- sop.sem_flg = 0;
-
- if (semop(semid, &sop, 1) == -1)
- errExit("semop");
-
- exit(EXIT_SUCCESS);
- }
-
- SEE ALSO
- brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), sysvipc(7)
- COLOPHON
- This page is part of release 5.10 of the Linux man-pages project. A description of the project, information about reporting bugs, and
- the latest version of this page, can be found at https://www.kernel.org/doc/man-pages/.
- Linux 2020-04-11 SHMOP(2)
共享内存示例 12.1c
- #include <stdio.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/wait.h>
-
- char msg[] = "Hello world";
-
- int main(void)
- {
- int shmid;
- pid_t pid;
-
- shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT);
-
- pid = fork();
-
- if(pid > 0)
- {
- char *p_addr;
- p_addr = shmat(shmid, NULL, 0);
-
- memset(p_addr, '\0', sizeof(msg));
- memcpy(p_addr, msg, sizeof(msg));
-
- shmdt(p_addr);
-
- waitpid(pid, NULL, 0);
- }
- else if(pid == 0)
- {
- char *c_addr;
- c_addr = shmat(shmid, NULL, 0);
-
- printf("Child process waits a short time: \n");
- sleep(3);
- printf("Child Process reads from shared memory: %s\n", c_addr);
- shmdt(c_addr);
- }
- else
- perror("fork");
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。