APUE 第三章习题 3.2 浅析

题目描述:编写一个与3.12节中dup2功能相同的函数,要求不能调用fcntl函数,并且有正确的出错处理。

题目分析:既然不能使用fcntl函数,那么我们就需要使用其他函数来达到类似的目的,这里列举出所有我们需要使用的函数。

1、  open函数:这里我们不应该指定一个文件描述符并尝试复制它,因为实际中我们不能知道我们指定的文件描述符就一定是合法的,这个文件描述符可能未被使用,如果这样的话就会导致后面一系列的操作失败。或者是这个文件描述符指向了一个已经打开,而且对用户非常重要的文件(操作不当的后果可想而知)。所以用open函数打开一个已经存在的文件是非常靠谱的,我们就可以复制open函数返回的文件描述符。当然,我们还要注意open函数调用时可能产生的错误进行处理。

2、  dup函数:在不能使用fcntl函数的情况下,dup函数是唯一的选择。注意dup函数的返回值,如果操作成功时返回可用的最小的文件描述符,出错时返回-1。当然,dup函数出错也是有可能的,比如说系统资源问题,或者是文件描述符用光(就现在的UNIX Like来说貌似不大可能,但是还是建议考虑一下)。

3、  输出函数:你需要将一些错误的信息输出到屏幕,告诉用户相关的错信息。

4、  close函数:用来关闭一个文件描述符,如果我们指定了将文件描述符a复制为b,如果文件描述符b被占用了,那么我们应该立即关闭它。

5、  atoi函数:将字符串转成数字,这个函数有可能会用到,具体需要看程序是如何实现的。

思路与实现细节:

         首先我们应该用open函数打开一个文件,并获取open函数返回的文件描述符,我们假定open函数获取的文件描述符为”file_flag”,要复制成的指定文件描述符为”obj_flag”。我们要考虑下面的一些问题,比如说打开文件操作失败,文件访问权限问题或者文件不存在都会导致该问题。当然,这似乎不应该是这个程序需要重点处理的问题,我们只需要返回一个适当的错误信息就可以了,不必去进行创建文件的操作。想一想,一个程序在悄无声息的就创建了一个用户以为存在(实际原来不存在)的文件而且还对其进行了操作。当然用户可能认为这些过程都是正确的(比如那个文件原来就存在),后果有可能是难以预测的。另外,通过open函数获取的文件描述符(file_flag)很可能与你指定要复制成的文件描述符(obj_flag)相同!这就涉及到了下一个问题,我们指定的文件描述符是否合法。

         指定的文件描述符不应该占用0~2这三个文件描述符,而且不能超过一个系统允许的上限,即OPEN_MAX,不过有些UNIX Like对其没有限制,但是建议指定的文件描述符(obj_flag)不要过大。如果指定的文件描述符与open函数获取的文件描述符相同当然也是不行的。如果出现文件描述符上述三种问题,应该返回错误,或者干脆让用户重新指定文件描述符。

         实现dup2函数的方式并不难,我们先要保证文件描述符3到obj_flag都被占满,这个只需要不断地调用函数:”dup(file_flag)”,直到其返回的文件描述符值不小于obj_flag。同时需要将这些通过dup函数得到的文件描述符记录下来,以便于以后的释放。之后我们调用函数”close(obj_flag)”,这样就保证了小于obj_flag的所有文件描述符都被占用,而文件描述符obj_flag是可用的。接下来调用”dup(file_flag)”就可以保证了返回的文件描述值为obj_flag(为严谨起见我们还是应该对此时dup函数的返回值进行判断)。如此就实现了与dup2函数相似的功能,但是不要忘记释放那些额外占用的文件描述符,我们需要及时的将其释放。否则如果该程序进程为关闭,就可能在某些UNIX Like系统上造成文件描述符不够用的情况。使用dup函数时,我们也要考虑是否可能存在着dup函数返回一个错误的情况,这时返回一个错误并输出一些相关的警告应该就可以OK了。

         这道题的思路大致如此。当然,即使是上面所有情况都考虑到了这个实现也没有足够好。因为这毕竟不是一个原子操作,如果有另外的一个进程对打开文件操作的话,上面思路实现的代码可靠性仍然没有保证。

代码参考:

#include <apue.h>

#include <fcntl.h>

 

#define MAXN 4096

#define exit_succeed 0

#define exit_failed -1

 

int cdup(const int file_flag, const int obj_flag)

{

     int i;

     int n;

     int top;

     int stack[MAXN];

 

     top = 0;

 

     if ((obj_flag>MAXN) || (obj_flag<3) || (obj_flag==file_flag))

     {

         printf("Obi_flag error!\n");

         return exit_failed;

     }

 

     while ((n = dup(file_flag)) < obj_flag)

     {

         if (-1 == n)

         {

              printf("System can not make a flag!\n");

              return exit_failed;

         }

 

         stack[top++] = n;

     }

 

     close(obj_flag);

 

     if (-1 == dup(file_flag))

     {

         printf("Function dup error\n");

         return exit_failed;

     }

 

     for (i=0; i<top; ++i)

     {

         close(stack[i]);

     }

 

     return exit_succeed;

}

 

int write_file(const int obj_flag)

{

     char buf[] = "JiaoZhuV5\n";

 

     if (write(obj_flag, buf, strlen(buf)) < 0)

     {

         printf("Write error\n");

         return exit_failed;

     }

 

     return exit_succeed;

}

 

int main(int argc, char *argv[])

{

     int obj_flag;

     int file_flag;

 

     if (3 != argc)

     {

         printf("Parameter error!\n");

         return exit_failed;

     }

 

     file_flag = open(argv[1], O_RDWR);

 

     if (-1 == file_flag)

     {

         printf("Errror! System can not open %s\n", argv[1]);

         return exit_failed;

     }

 

     obj_flag = atoi(argv[2]);

 

     if (exit_failed != cdup(file_flag, obj_flag))

     {

         if (exit_failed == write_file(obj_flag))

         {

              return exit_failed;

         }

     }

 

     return exit_succeed;

}

         上面代码仅供参考,若发现有任何不妥的地方,欢迎各位的批评指正。

转载于:https://www.cnblogs.com/yangheyu/archive/2013/03/23/2976667.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
习题 9.2: 编写一个程序,创建一个共享内存区,然后将一个文件映射到该共享区中。编写两个程序,一个程序将数据写到共享区中,另一个程序读取共享区中的数据,并将结果写到标准输出。使用信号量进行同步。 解答: 以下是一个简单的实现: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/shm.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <semaphore.h> #define SHM_SIZE 1024 // 共享内存区大小 #define SEM_NAME "/mysem" // 信号量名称 int main(int argc, char *argv[]) { int shm_fd; void *shm_ptr; sem_t *sem_ptr; int value = 0; // 创建共享内存区 shm_fd = shm_open("myshm", O_CREAT | O_RDWR, 0666); ftruncate(shm_fd, SHM_SIZE); // 映射共享内存区 shm_ptr = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); // 创建信号量 sem_ptr = sem_open(SEM_NAME, O_CREAT, 0666, 1); // 写入数据 sem_wait(sem_ptr); // 申请信号量 sprintf(shm_ptr, "%s", "Hello, world!"); sem_post(sem_ptr); // 释放信号量 // 读取数据 sem_wait(sem_ptr); // 申请信号量 printf("%s\n", (char*)shm_ptr); sem_post(sem_ptr); // 释放信号量 // 销毁信号量 sem_close(sem_ptr); sem_unlink(SEM_NAME); // 解除共享内存区映射 munmap(shm_ptr, SHM_SIZE); // 销毁共享内存区 shm_unlink("myshm"); return 0; } ``` 在这个程序中,我们使用 `shm_open` 和 `ftruncate` 函数创建了一个大小为 `SHM_SIZE` 的共享内存区,并使用 `mmap` 函数将其映射到进程的地址空间中。然后,我们使用 `sem_open` 函数创建了一个信号量,并在写入数据和读取数据的过程中使用 `sem_wait` 和 `sem_post` 函数进行同步。最后,我们使用 `munmap` 函数解除了共享内存区的映射,并使用 `shm_unlink` 函数销毁了共享内存区。 编写第二个程序时,只需要将写入数据和读取数据的顺序颠倒即可。同时,需要使用相同的共享内存区和信号量名称。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值