Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在另一个子进程写入文本文件时锁定该文本文件_C_Linux_Fork_File Writing_File Locking - Fatal编程技术网

C 在另一个子进程写入文本文件时锁定该文本文件

C 在另一个子进程写入文本文件时锁定该文本文件,c,linux,fork,file-writing,file-locking,C,Linux,Fork,File Writing,File Locking,我用c实现了多个分叉客户端,它们都应该写入一个公共文件。由于来自这些套接字的信息在文件目标中都被弄乱了,所以到目前为止,这一操作失败了。 这是我的密码 FILE *Ufptr; Ufptr = fopen("Unsorted_busy_list.txt","a+"); fprintf(Ufptr, "%s:%d\n",inet_ntoa(newAddr.sin_addr),ntohs(newAddr.sin_port)); fclose(Ufptr); 有人告

我用c实现了多个分叉客户端,它们都应该写入一个公共文件。由于来自这些套接字的信息在文件目标中都被弄乱了,所以到目前为止,这一操作失败了。 这是我的密码

    FILE *Ufptr;
    Ufptr = fopen("Unsorted_busy_list.txt","a+");

    fprintf(Ufptr, "%s:%d\n",inet_ntoa(newAddr.sin_addr),ntohs(newAddr.sin_port));
    fclose(Ufptr);
有人告诉我,在文件上使用fcntl和互斥锁就可以了,但我是新手,不知道如何在文件编写过程中实现这一点。
任何帮助

正如我在评论中提到的,如果父进程使用子进程的输出,则通常更容易使用Unix域数据报套接字对或每个子进程一对。Unix域数据报套接字保留消息边界,以便在单个recv中接收使用send成功发送的每个数据报。您甚至可以以二进制结构发送数据。不需要锁。如果为每个子级使用套接字对,则可以轻松地将父端设置为非阻塞,并使用select或poll在单个循环中读取所有数据报

回到问题本身

下面是append_文件名、格式等的示例实现。。。使用POSIX.1-2008写入文件,使用基于fcntl的建议记录锁:

#define  _POSIX_C_SOURCE  200809L
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

int append_file(const char *filename, const char *format, ...)
{
    struct flock  lock;
    va_list       args;
    int           fd, cause;

    /* Sanity checks. */
    if (!filename || !*filename)
        return errno = EINVAL;

    /* Open the file for appending. Create if necessary. */
    fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0666);
    if (fd == -1)
        return errno;

    /* Lock the entire file exclusively.
       Because we use record locks, append_file() to the same
       file is NOT thread safe: whenever the first descriptor
       is closed, all record locks to the same file in the process
       are dropped. */
    lock.l_type = F_WRLCK;
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;
    if (fcntl(fd, F_SETLKW, &lock) == -1) {
        cause = errno;
        close(fd);
        return errno = cause;
    }

    if (format && *format) {
        cause = 0;
        va_start(args, format);
        if (vdprintf(fd, format, args) < 0)
            cause = errno;
        va_end(args);
        if (cause) {
            close(fd);
            return errno = cause;
        }
    }

    /* Note: This releases ALL record locks to this file
             in this process! */
    if (close(fd) == -1)
        return errno;

    /* Success! */
    return 0;
}

int main(int argc, char *argv[])
{
    int arg = 1;

    if (argc < 3) {
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
        fprintf(stderr, "       %s FILENAME STRING [ STRING ... ]\n", argv[0]);
        fprintf(stderr, "\n");
    }

    for (arg = 2; arg < argc; arg++)
        if (append_file(argv[1], "%s\n", argv[arg])) {
            fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno));
            return EXIT_FAILURE;
        }

    return EXIT_SUCCESS;
}
如果所有写入程序都使用上述append_文件来追加到该文件,则可以在任何时候安全地重命名该文件。请注意,如果一个或多个进程在重命名过程中等待释放记录锁,那么在重命名之后,它们可能会对文件进行最后的追加

要截断该文件,请首先对其使用独占锁,然后调用ftruncatefd,0


要读取文件,请使用基于fcntl的共享锁frdlck,允许其他读取器同时读取;或者F_WRLCK,如果您打算在读取当前内容后自动截断文件,或者您可能会在末尾看到部分最终记录。

这可能会有所帮助:POSIX系统中的大多数文件锁定是“建议性”而不是“强制性”的。您需要一个进程间互斥体,而不是进程内互斥体,因为您的进程有叉而不是线程。而不是一个公共文件,您应该考虑使用创建到int fd(2)的UNIX域数据报套接字对;通过socketpairAF_UNIX、SOCK_DGRAM、0、fd,每个孩子可能有一个套接字对。Unix域数据报套接字保留消息边界,因此每次成功发送都使用一个recv接收。您甚至可以发送/接收二进制消息,例如成对的struct in_addr或struct in 6_addr。无需锁定,并且父级中的简单非阻塞select/poll+recv循环可以从多个客户端接收,不会出现问题。谢谢@NORMAL ANALL。但是上面的解决方案在linux上也有效吗?@MikeM:是的。事实上,我在Linux上编写并测试了它