如何在不使用close()的情况下关闭使用shm_open()打开的文件描述符(FD)?

4

我希望关闭一个使用 shm_open 打开的文件描述符。

以下是代码:

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>             
 #include <sys/file.h>           
 #include <sys/mman.h>          
 #include <sys/wait.h>

 void errorAndExit(const char *msg)
 {
     perror(msg);
     exit(EXIT_FAILURE);
 }

 int main(int argc, char *argv[])
 {
      /* shm_open recommends using a leading '/' in
      the region name for portability, but Linux
      doesn't require it. */

      const char *memname = "/myMkfifo.txt";

      // Use one page for this example

      const size_t region_size = sysconf(_SC_PAGE_SIZE);

     /* Create the shared memory region.
      Notice the args are identical to open(2).*/

     int fd = shm_open(memname, O_CREAT | O_TRUNC | O_RDWR, 0666);
     if (fd == -1)
         errorAndExit("shm_open");

    /* Allocate some memory in the region. We use ftruncate, but
     write(2) would work just as well. */

     int r = ftruncate(fd, region_size);
     if (r != 0)
         errorAndExit("ftruncate");

    // Map the region into memory.

     void *ptr =
         mmap(0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
              0);
     if (ptr == MAP_FAILED)
         errorAndExit("mmap");

     // Don't need the fd after the mmmap call.

     close(fd);
     pid_t pid = fork();

     if (pid == 0)   // son
     {
         // Child process inherits the shared memory mapping.

         u_long *d = (u_long *) ptr;
         *d = 200;
         printf("I'm the child process and I wrote: %#lx\n", *(u_long *) d);
         exit(0);
     }


     else    
     {   /* child
          Synchronize with the child process. */

         int status;
         waitpid(pid, &status, 0);

         // Parent process sees the same memory.

         printf("I'm the father process , and my child wrote: %#lx\n", *(u_long *) ptr);

     }

     // errorAndExit with the memory, umap it.

     r = munmap(ptr, region_size);
     if (r != 0)
         errorAndExit("munmap");

     // Remove the shared memory region.

     r = shm_unlink(memname);
     if (r != 0)
         errorAndExit("shm_unlink");

    return 0;
}

如何在不使用 close() 的情况下关闭 fd

谢谢。


根据http://linux.die.net/man/3/shm_open ,你可以使用“shm_unlink()”来释放从“shm_open()”获取的文件描述符。这是你要找的吗? - MatthewD
4
通常当你想要做“不使用Y的X”时,最好解释一下为什么,因为这些看似随意的限制可能会让人感到相当沮丧。 - unwind
3
不使用 "close" 的意义在哪里?如果有另一种系统调用可以起到同样作用的话,不使用它会带来什么好处? - Mat
只需执行 exit(0) 即可关闭所有文件描述符。 - Jens Gustedt
3
@ron:你希望获得什么?你为什么认为“关闭”是一个问题?你试图解决什么问题? - Mat
显示剩余6条评论
2个回答

4

对于我来说,这听起来像是一个谜题:如何在不调用fd上的close的情况下关闭文件描述符呢?以下是一种方法:

int close_without_close (int fd) {
    if (dup2(!fd, fd) < 0) return -1; // assumes 0 and 1 are open
    return close(!fd);
}

这是另一个例子:
int close_without_close2 (int fd) {
    if (fcntl(fd, fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) return -1;
    switch (fork()) {
    case -1: return -1;
    case 0:  break;
    default: exit(EXIT_SUCCESS);
    }
    return 0;
}

好的,在执行exec之后,第二个不起作用。唉...

还有一个:

int close_without_close3 (int fd) {
    return syscall(SYS_close, fd);
}

@jxh:而且它关闭了错误的文件描述符。这个答案中的所有解决方案都是错误的,所以我不明白为什么它被接受为答案... - R.. GitHub STOP HELPING ICE
@R..: dup2()会在将!fd(大多数情况下是0)复制到fd之前关闭fd - jxh
dup2 会释放 fd 所引用的打开文件的引用,但文件描述符槽位随后被占用,指向作为标准输入或标准输出的打开文件的引用。此外,您随后调用 close(这是问题禁止的),关闭标准输入或标准输出通常是危险和不正确的做法。 - R.. GitHub STOP HELPING ICE
@R..:所以使用dup2()时,我不会关闭错误的fd。关闭描述符01是有风险的,但这并不意味着它没有先例。 - jxh
@R..:这只是个玩笑。假设否定运算符和close()函数调用是可交换的。 - jxh
显示剩余2条评论

2
这是一种(昂贵的...)绕过 close() 的方法...
#include <unistd.h>
#include <fcntl.h>

int main (int argc, char **argv)
{
int val;
int fd = -1;

val = fcntl(fd, F_GETFD, 0);
val |= FD_CLOEXEC;
fcntl(fd, F_SETFD, val);

execve(argv[0], argv, NULL);
return 0; /* not reached */
}

这也是不正确的。argv[0] 不需要是您可执行文件的有效路径名;它是由调用您的程序的程序提供的任意字符串。 - R.. GitHub STOP HELPING ICE
main函数的调用可以由调用进程控制(例如,它可以设置argv[0] = "/bin/tine";,但是根据问题的阅读,我得出结论OP知道这些东西。从本质上讲,execXXX()取消映射所有内存映射,因此这种说法也是错误的。但是一般来说,我认为对于一个荒谬的问题,一个荒谬的答案是合适的。而且使用close on exec的想法也不错。 - wildplasser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接