C语言的clone与mmap调用
2021-03-13 07:29
标签:shared 导致 launch lock 另一个 tls ext function 进程间 linux 创建线程(pthread_create)和进程(fork)的过程非常类似,都是主要依赖 clone 函数,只不过传入的参数不同而已。 如此一来,内核只需要实现一个 clone函数,就既能创建进程,又能创建线程了,例如; 创建进程: 创建线程: 其实,linux 内核没有严格区分线程和进程,也没有准备特别的调度算法或是定义特别的数据结构来描述线程。相反,线程仅仅被视为一个与其他进程共享某些资源的进程,在 linux 中,线程看起来就像是一个轻量级的进程(light weight process)。 看下clone函数原型: glibc clone函数是对clone系统调用的一个封装。 能够看出,clone 函数是一个不定参数的函数。它主要用于创建新的进程(也包括线程,因为线程是“特殊”的进程),调用成功后,返回子进程的 tid,如果失败,则返回 -1,并将错误码设置再 errno。 clone 函数的第1个参数fn是一个函数指针;第2个参数child_stack是用于创建子进程的栈(注意需要将栈的高地址传入);第3个参数flags,就是用于指定行为的参数了。 flags参数列举如下: 看个用clone() 创建线程的例子 说明: 输出结果: main: 28942-28942 28943-28943 testOcupMem exit 1:1606723499039 clonePid: 28942-28945 28945-28945 testOcupMem exit 2:1606723500039 clonePid: 28942-28986 28986-28986 testOcupMem exit 3:1606723501039 clonePid: 28942-28989 28989-28989 testOcupMem exit 4:1606723502039 clonePid: 28942-29008 29008-29008 testOcupMem exit 从输出内容可见: 1、在testOcupMem函数打印的getpid都是同一个值,说明每次clone创建的线程属于同一个父进程(main进程),但 tid 各不相同; 2、为什么main函数for循环的 clonePid 日志会重复2次呢(看时间戳应该是同一个时间点打印的)?据我感觉应该是clone调用会在一个新线程开始执行testOcupMem函数,而这个函数如果后于printf执行,可能创建的新线程也执行了printf,这样当main线程打印的时候就有2条日志。当然,这个只是我的猜测,还有待验证。 PS:如果想用clone创建进程,在上面的例子中,把clone函数的flags参数去掉 CLONE_VM | CLONE_FS | CLONE_FILES 即可。 mmap函数把一个文件或一个POSIX共享内存区对象映射到调用进程的地址空间,使用该函数有3个目的: 1、使用普通文件以提供内存映射I/O; 2、使用特殊文件以提供匿名内存映射; 3、使用shm_open以提供无亲缘关系进程间的POSIX共享内存区。 存储映射I/O使一个磁盘文件的全部或部分内容映射到用户空间中,将进程读写文件的操作变成了读写内存的操作(不再需要read/write调用)。 API: 说明: mmap函数中的prot参数 PROT_READ 映射区可读 PROT_WRITE 映射区可写 PROT_EXEC 映射区可执行 PROT_NONE 映射区不可访问 mmap函数中的flags参数 MAP_PRIVATE 私有,对映射区的写操作会导致创建映射文件的一个私有副本 MAP_SHARED 对映射区的写操作直接修改原始文件,多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,另一个进程也会看到这种变化 MAP_FIXED 返回值必须等于addr,不利于移植性 MAP_ANONYMOUS 匿名映射,此时忽略fd,且映射区域无法与其它进程共享,这个选项一般用来扩展heap MAP_DENYWRITE MAP_LOCKED msync函数中的flags参数, MS_ASYNC 异步写 MS_SYNC 同步写 MS_INVALIDATE 从文件中读回数据 注意:调用fork函数,子进程继承存储映射区(子进程复制父进程的地址空间,而存储映射区是该地址空间的一部分),但调用exec之后的程序则不继承此存储映射区。 如下,fd=0,没有关联任何文件; 如下,以MAP_SHARED 映射指定文件,修改后可以同步到文件中; 多进程之间共享 参考: https://eli.thegreenplace.net/2018/launching-linux-threads-and-processes-with-clone/ https://blog.popkx.com/c-language-actual-warfare-29-how-does-the-linux-kernel-create-processes-and-threads/ C语言的clone与mmap调用 标签:shared 导致 launch lock 另一个 tls ext function 进程间 原文地址:https://www.cnblogs.com/chenny7/p/14060906.html
clone
clone(SIGCHLD)
clone(CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD)
/* Prototype for the glibc wrapper function */
#include
//#define _GNU_SOURCE
#include
0:1606723498039 clonePid: 28942-28943
1:1606723499039 clonePid: 28942-28945
2:1606723500039 clonePid: 28942-28986
3:1606723501039 clonePid: 28942-28989
4:1606723502039 clonePid: 28942-29008mmap
#include
MAP_ANONYMOUS 用法
void annoymap(int N) {
int *ptr = (int *) mmap(NULL, N * sizeof(int),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
0, 0);
if (ptr == MAP_FAILED) {
printf("Mapping Failed\n");
return;
}
// Fill the elements of the array
for (int i = 0; i ) {
ptr[i] = i;
}
// print
for (int i = 0; i ) {
printf("[%d] ", ptr[i]);
}
printf("\n");
if (0 != munmap(ptr, 10 * sizeof(int))) {
printf("UnMapping Failed\n");
return;
}
}
文件IO映射
void filemap(const char* path) {
int fd;
void *start;
struct stat sb;
fd = open(path, O_RDWR);
fstat(fd, &sb);
start = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (start == MAP_FAILED) {
printf("mmap failed\n");
return ;
}
close(fd);
printf("%s", start);
strncpy((char*)start, "say hi", 6);
munmap(start, sb.st_size);
}
共享内存映射
void sharememory(int size) {
char parent_message[] = "hello";
void* shmem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
memcpy(shmem, parent_message, sizeof(parent_message));
if (fork() == 0) {
printf("Child read: %s\n", shmem);
char child_message[] = "goodbye";
memcpy(shmem, child_message, sizeof(child_message));
printf("Child wrote: %s\n", shmem);
} else {
printf("Parent read: %s\n", shmem);
sleep(1);
printf("After 1s, parent read: %s\n", shmem);
}
}
上一篇:排序算法:选择排序