ZBLOG

#include #include #include #include #include #include "sem_pv.h" int main(void) { key_t key; int pid,fd,semid,n; char str[80]; key=ftok(".",5); semid=sem_init(key); fd=open("test.txt",O_...

这个代码片段展示了一个父子进程之间使用信号量来进行互斥访问文件的例子。让我们逐行分析这个代码的工作原理和可能存在的问题。

代码分析

  1. 引入头文件

    #include <unistd.h>
    #include <sys/stat.h>
    #include <fcntl.h> 
    #include <sys/wait.h>
    #include <string.h>
    #include "sem_pv.h"
    
    • unistd.hsys/stat.hfcntl.h 等头文件用于提供POSIX API。
    • "sem_pv.h" 应该是你自己实现的信号量操作相关的头文件,包含了 sem_init, sem_p, sem_v, 和 sem_rmv 的声明。
  2. 主函数入口

    int main(void)
    {
       key_t key;
       int pid, fd, semid, n; 
       char str[80];
       key = ftok(".", 5);
       semid = sem_init(key);
       fd = open("test.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
    
    • 使用 ftok 生成一个唯一的键值,用于创建信号量。
    • 创建/打开一个名为 test.txt 的文件以供读写。如果文件不存在,则创建它。
  3. 创建子进程

    while ((pid = fork()) == -1); /* Loop until fork is successful */
    if (pid == 0) /* Child process */
    { 
        sleep(1);
        sem_p(semid);
        lseek(fd, SEEK_SET, 0);
        read(fd, str, sizeof(str));
        sem_v(semid);
        printf("child: read str from test file: %s\n", str);
        exit(0);
    } 
    else /* Parent process */
    {
        sem_p(semid);
        printf("parent: please enter a str for test file (strlen<80):\n");
        gets(str); // Warning: unsafe function
        n = strlen(str); lseek(fd, SEEK_SET, 0);
        write(fd, str, n);
        sem_v(semid);
        wait(0); // Wait for child to finish
        close(fd); // Close the file descriptor
        sem_rmv(semid); // Remove semaphore
        exit(0);
    }
    
  4. 功能说明

    • 父进程先请求信号量,然后等待用户输入字符串并写入到文件中。
    • 子进程在稍微延迟后请求信号量,读取同一文件中的内容,并打印出来。

存在的问题及改进建议

  1. 使用不安全的 gets() 函数

    • gets() 是一个不安全的函数,因为它不会检查缓冲区溢出。应替换为更安全的输入方式,如 fgets()
     fgets(str, sizeof(str), stdin); // Safe alternative to gets()
    
  2. 信号量初始化和错误处理

    • 在调用 sem_init(key) 和其他系统调用后,应该对返回值进行错误检查,以确保程序在出现错误时能够适当处理。
  3. 没有考虑并发访问问题

    • 如果多个子进程同时尝试读取或写入同一个文件,可能会产生竞争条件,因此需要确保每个进程都能正确地获取和释放信号量。
  4. 避免魔法数字

    • 对于像“5”和“80”这样的魔法数字,可以用常量或宏定义来代替,使得代码更加可读。
  5. 资源管理

    • 确保在所有情况下(包括异常退出)都能正确关闭打开的文件描述符,以及移除信号量。

完整示例(带改进)

下面是带有上述建议的小改动版本:

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h> 
#include <sys/wait.h>
#include <string.h>
#include "sem_pv.h"

#define MAX_STR_LEN 80

int main(void)
{
    key_t key;
    int pid, fd, semid;
    char str[MAX_STR_LEN];

    key = ftok(".", 5);

    if ((semid = sem_init(key)) == -1) {
        perror("Failed to initialize semaphore");
        exit(EXIT_FAILURE);
    }

    if ((fd = open("test.txt", O_RDWR | O_CREAT | O_TRUNC, 0644)) == -1) {
        perror("Failed to open file");
        exit(EXIT_FAILURE);
    }

    if ((pid = fork()) == -1) {
      perror("Fork failed");
      exit(EXIT_FAILURE);
	}

	if (pid == 0) { // Child process
	    sleep(1);

	    sem_p(semid);

	    lseek(fd, SEEK_SET, 0);
	    read(fd, str, sizeof(str));

	    sem_v(semid);

	    printf("child: read str from test file: %s\n", str);

	    exit(EXIT_SUCCESS);

	} else { // Parent process

		// Ensure proper use of fgets instead of gets
		sem_p(semid);

		printf("parent: please enter a string for test file (max length %d):\n", MAX_STR_LEN-1);
		fgets(str, sizeof(str), stdin);

		int n = strlen(str); 
		lseek(fd, SEEK_SET ,0 );
		write(fd,str,n);

		// Release semaphore before waiting on child process.
 		// Otherwise we will have a deadlock situation.
	 	sem_v(semid); 

	 	wait(NULL); // Wait for child to finish

	 	close(fd); // Close the file descriptor
	 	
	 	if (sem_rmv(semid) == -1) {
		    perror("Failed to remove semaphore");
		 	exit(EXIT_FAILURE);
	  }
	  
	  exit(EXIT_SUCCESS);}
}

通过这些改动,你可以提高程序的安全性、健壮性以及可读性。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=5610

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?