系统环境:deepin Linux,语言环境:Linux C
欢迎大家转载,转载请注明出处,谢谢!
理论基础:
相关函数:
多进程相关:
fork()
:
原型:
#include
#include
pid_t fork(void);
说明:
通过复制调用者来创建新进程。这个新的进程简称为子进程。调用该函数的进程称为父进程。
子进程和父进程运行在不同的内存空间中。在调用该函数的时候,两个进程内存空间都拥有相同的内容。其中一个进程执行的内存写入,文件映射和解除映射操作不会影响到另一个进程。该函数的返回值在父子进程中不同,在父进程中返回子进程PID,在子进程中返回0。
wait()
:
函数原型及头文件:
#include
#include
pid_t wait(int *stat_loc);
函数说明:
当调用这个函数的时候,当前进程会阻塞等待,该进程的某个子进程运行结束为止。
该结束的子进程的返回状态被存储在wait()函数的参数stat_loc变量中。
system();
函数原型及头文件:
#include
#include
int system(char *command);
函数说明:
创建新的进程,执行制定命令。
exec函数族:
函数原型及头文件:
#include
int execl(cONst char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *filename, char *const argv[], char *const envp[]);
函数说明:
exec 函数族
execve 函数是该族的基础函数,其他函数是由该函数封装而来
exec 族被用启动新的指定路径下的程序来替换当前的程序。
函数名称后面的后缀不同参数不尽相同见下面附录1。
exit()
:
函数原型及头文件:
#include
void exit(int status);
函数说明:
终止进程并返回状态码。
多线程相关:
pthread_create()
:
函数原型及头文件:
#include
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
函数说明:
start_routine()
函数指针指向的函数来执行,arg参数是该函数指针指向的函数唯一的参数。pthread_exit()
函数,并确定退出状态值,该值可用于该进程中的调用phread_join()
的其他线程。phread_exit()
并带有返回值。pthread_cancel()
)exit()
函数,或者在主函数中执行return
。这会导致该进程中所有线程终止。pthread_join()
:
函数原型及头文件:
#include
int pthread_join(pthread_t thread, void **retval);
函数说明:
pthread_detach()
:
函数原型及头文件:
#include
int pthread_detach(pthread_t thread);
函数说明:
该函数会把由thread参数指向的线程标记为分离。一个被标记分离的线程终止后,该线程的资源会被系统自动收回,不需要其他线程进程其他的操作。尝试标记已经分离的线程是不明操作,会导致未知错误。
pthread_self()
:
函数原型及头文件:
#include
pthread_t pthread_self(void);
函数说明:
thread_create()
函数返回的thread值相同。pthread_equal
:
函数原型及头文件:
#include
int pthread_equal(pthread_t t1, pthread_t t2);
函数说明:
pthread_exit()
:
函数原型及头文件:
#include
void pthread_exit(void *retval);
函数说明:
该函数会终止调用该函数的线程,并通过参数retval返回一个值,该值可用于同一进程中的其他线程调用pthread_join()
。
线程同步机制:
互斥:
pthread_mutex_init()
、pthread_mutex_destroy()
:
函数原型及头文件:
#include
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
函数说明:
pthread_mutex_destroy()
:
pthread_mutex_init()
重新初始化。在互斥锁被销毁后引用该互斥锁会导致未定的引用的错误。pthread_mutex_init()
:
pthread_mutex_lock()
、pthread_mutex_trylock()
和pthread_mutex_unlock
:
函数原型及头文件:
#include
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
函数说明:
pthread_mutex_lock()
pthread_mutex_trylock()
pthread_mutex_unlock()
读写锁:
``pthread_rwlock_init()、
pthread_rwlock_destory()`:
函数原型及头文件:
#include
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
函数说明:
pthread_rwlock_destory()
函数将销毁rwlock引用的读写锁对象,并释放锁使用的所有资源。pthread_rwlock_rdlock()
:
函数原型及头文件:
#include
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
函数说明:
两个函数函数都会对由rwlock引用的读写锁解开读锁。但是对于pthread_rwlock_rdlock()
函数如果写入权限没有上锁并且互斥锁上没有写入权限被阻塞,则调用线程获取读锁定。调用该函数的线程读权限会被上锁。try函数遇到这种情况会返回调用失败两个函数都是成功返回0。
pthread_rwlock_wrlock()
:
函数原型及头文件:
#include
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
函数说明:
两个函数同样都会为调用者加写权限锁,但是try函数回去尝试,也就是说如果任何线程当前持有rwlock(用于读或写),函数将调用失败。但是另一个函数遇到这种情况会阻塞。函数执行成功返回0。
pthread_rwlock_unlock()
:
函数原型及头文件:
#include
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
函数说明:
该函数将释放由rwlock引用的读写锁对象上的锁。 如果读写锁定rwlock未被调用线程保持,则结果是不确定的。
条件变量:
thread_cond_init()
、thread_cond_destory()
函数原型及头文件:
#include
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
函数说明:
pthread_cond_destroy()
函数将销毁由cond指定的给定条件变量; 实际上,对象会处于未初始化状态。可以使用pthread_cond_init()
重新初始化已销毁的条件变量对象; 在对象被销毁之后引用该对象的结果是未定义的。pthread_cond_init()
函数应使用attr引用的属性初始化cond引用的条件变量。
thread_cond_wait()
、thread_cond_timedwait()
:
函数原型及头文件:
#include
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
函数说明:
两个函数都会阻塞条件变量。 应用程序应确保在调用线程锁定互斥锁的情况下调用这些函数; 否则,会产生错误或未定义的行为(对于其他互斥锁)。
thread_cond_signal()
、thread_cond_broadcast()
:
函数原型及头文件:
#include
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
函数说明:
pthread_cond_broadcast()
函数将取消阻止当前在指定条件变量cond上阻塞的所有线程。pthread_cond_signal()
函数应解除阻塞在指定条件变量cond上阻塞的至少一个线程(如果在cond上阻塞了任何线程)。
共享内存相关:
shmget()
:
函数原型及头文件:
#include
#include
int shmget(key_t key, size_t size, int shmflg);
函数说明:
该函数返回与参数key相关联的共享内存片段的标识符(identifier)。
该函数可以用于获取先前创建的共享内存的idenfifier(当shmflg为0并且key值不是IPC_PRIVATE< 预定义宏,见附录3 >的时候)
该函数还可以用于创建一个新共享内存,新的共享内存大小为size参数向上取整到PAGE_SIZE(预定义宏,见附录3)。使用该函数创建新的共享内存需满足如下条件:
如果参数shmflg指定了IPC_CREAT和IPC_EXECL并且key 已经存在与其相关联的共享内存,那么shmget函数创建新的共享内存失败,并且erron会被设置为EEXIST。(这有点像O_CREAT | O_EXCL 组合对于open()函数带来的影响)
shmflg参数的取值如下:
IPC_CREAT IPC_EXCL、SHM_HUGETLB、SHM_HUGE2MB(SHM_HUGE_1GB)、SHM_NORESERVE(详情见附录3)
shmat()
、shmdt()
:
函数原型及头文件:
#include
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
函数说明:
shmctl()
:
函数原型及头文件:
#include
#include
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
该函数执行由cmd参数指定的操作,cmd参数存储在由shmid参数存储的识别码指向的共享内存段。
buf参数是一个shmid_ds结构体指针,shmid_ds结构体在头文件
struct shmid_ds {
struct ipc_perm shm_perm; /* 所有权和权限 */
size_t shm_segsz; /* 段大小(单位:字节) */
time_t shm_atime; /* 最后的链接时间 */
time_t shm_dtime; /* 最后的断开链接时间 */
time_t shm_ctime; /* 最后的更改时间 */
pid_t shm_cpid; /* 创建者的PID */
pid_t shm_lpid; /* 最后的shmat()函数或shmdt()函数的pid */
...
};
ipc_perm结构体的定义如下(其中udi、gid和mode可设置为IPC_SET):
struct ipc_perm {
key_t __key; /* 提供给shmget()函数的键值 */
uid_t uid; /* 有效的拥有者的UID */
gid_t gid; /* 有效的拥有者的GID */
uid_t cuid; /* 有效的创建者UID */
gid_t cgid; /* 有效的创建者GID */
unsigned short mode; /* 权限 + SHM_DEST 和 SHM_LOCKED 标记 */
unsigned short __seq; /* 序列号 */
};
cmd参数的有效值如下:
IPC_STAT、IPC_SET IPC_RMID、IPC_INFO、SHM_INFO、SHM_STAT、SHM_LOCK、SHM_UNLOCK 。
附录1(摘自网络):
后缀 | 参数 |
---|---|
l | 接收以逗号为分隔的参数列表,以NULL为结束符 |
v | 接收以NULL为结束的字符串数组 |
p | 接收以NULL为结束的字符串数组指针,并可以利用DOS的PATH变量查找子程序文件 |
e | 传递环境变量。 |
附录2(摘自网络):
附录三(翻译自man手册):
宏名称 | 意义 |
---|---|
IPC_CREAT | 创建一个新的段,如果这个标志没有被使用,shmget()函数将会寻找与这个段相对应的key参数值,并且检查使用者是否有读取这个段的权限。 |
IPC_EXCL | 该标志与IPC_BREAT一起被用作确认本次创建共享内存的调用成功与否。 |
IPC_PRIVATE | 它不是一个标志字段,而是一个key_t类型的值,如果函数调用的时候key参数中存储这个特殊的值,系统调用会忽略除了shmflg中最不重要的9位意外的所有并且创建一个新的共享内存。 |
IPC_STAT | 从内核中拷贝shmid中由buf指向的shmid_ds结构相关的数据结构信息。对于共享内存段调用者必须拥有可读权限。 |
IPC_SET | 往参数buf指针指向的shmid_ds结构体的某些成员写入与该共享内存段相关联的内核数据结构,并且更新该结构体中的shm_ctime成员。以下成员可能会被改变:shm_perm.uid、shm_perm.gid和(最不重要的九位)shm_perm.mode。调用进程的有效UID必须与拥有者(shm_perm.uid)或共享内存的创建者(shm_per.cuid)相匹配,或者与一定是拥有特权的调用者相匹配。 |
IPC_RMID | 标记被销毁的共享内存段,实际上,这个共享内存段实在进程销毁的时候被销毁。(当shmid_ds相关构成员shm_nattch为空的时候)。调用者必须是共享内存的拥有者或者创建者,或者拥有特权。buf参数被忽略。 |
SHM_NORESREVE | (从linux内核2.6.15以后)这个标志与mmap()函数的MAP_NORESERVE 标志具有同样的目的。不保留交换空间对于共享内存段,当交换空间被保留了,他会保证共享内存是可用的。当交换空间没有被保留,并且物理内存不可用,那么可能会在写入时获取SIGSEGV。也可以查阅/proc/sys/vm/overcommit 文件。 |
SHM_REMAP | (LInux特有)这个标志指定了在共享内存段中从shmaddr参数开始到段最后的范围内的段映射应该被替换成现有的映射。(一般情况下,一个EINVAL错误可能是由于一个映射在地址范围内已经存在)在这个案例中,shmaddr参数必须不为空。 |
SHM_RDONLY | 以只读的方式链接共享内存段。进程对共享内存段必须有读取权限。如果标志没有被指定,那么共享内存段会被以可读可写方式链接,并且进程对于该共享内存段必须拥有可读和可写权限。但这不意味着对共享内存段有只写权限。 |
SHM_EXEC | (Linux特有,从linux2.6.9以后)允许执行共享内存段中的内容。调用者对于共享内存段必须拥有可执行权限。 |
SHM_HUGETLB | (从linux内核2.6版以后)为共享内存段分配巨大空间,详情见linux内核源码文件中Documentation/vm/hugetlbpage.txt 获取更多信息。 |
SHM_HUGE2MB,SHM_HUGE1GB | (从linux内核3.8之后)与SHM_HUGETLB一起被用作选择替代hugetlb大页面的大小(分别是2MB和1GB),并且支持超过hugetlb大页面的大小。 |
参考资料:
参考网站:多进程编程总结、C语言多进程编程、多线程和多进程的区别(小结)、百度百科:程序并发执行、linux下c语言编程exec函数使用
参考书籍:C语言核心技术 、man手册