Клон (2) с CLONE_FILES утечки fcntl блокирует?
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define __USE_GNU
#include <sched.h>
void init_lock(struct flock *f)
{
f->l_type = F_WRLCK; /* write lock set */
f->l_whence = SEEK_SET;
f->l_start = 0;
f->l_len = 0;
f->l_pid = getpid();
}
int lock(int fd, struct flock *f)
{
init_lock(f);
if(fcntl(fd, F_SETLKW, f) == -1) {
fprintf(stderr,"fcntl() failed: %s\n", strerror(errno));
return -1;
}
return 0;
}
int unlock(int fd, struct flock *f)
{
f->l_type = F_UNLCK;
if(fcntl(fd, F_SETLK, f) == -1) {
fprintf(stderr, "fcntl() failed: %s\n", strerror(errno));
return -1;
}
return 0;
}
int file_op(void *arg)
{
char buff[256];
int fd = (int) arg, n;
struct flock my_lock;
printf("Trying to get lock\n");
if(lock(fd, &my_lock) == -1) { /* lock acquired by a thread */
return -1;
}
printf("Got lock: %d\n", getpid()); /* I am printing thread id after lock() */
printf("Enter string to write in file : ");
scanf("%s", buff);
if((n=write(fd, &buff, strlen(buff))) == -1) {
fprintf(stderr, "write() failed: %s\n", strerror(errno));
}
if(unlock(fd, &my_lock) == -1) {
return -1;
}
printf("Lock Released: %d\n", getpid());
return 0;
}
int main()
{
char *stack;
int fd, i=0, cid, stacksize;
if((fd = open("sample.txt", O_CREAT | O_WRONLY | O_APPEND, 0644)) == -1) {
printf("Error in file opening\n");
exit(1);
}
stacksize = 3*1024*1024;
for(i=0; i<5; i++) {
stack = malloc(stacksize);
if((cid = clone(&file_op, stack + stacksize, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD, (void *) fd)) == -1) {
fprintf(stderr,"clone() failed: %s\n", strerror(errno));
break;
}
}
sleep(30);
close(fd);
return 0;
}
Я хочу, чтобы каждый clone () ожидал блокировки. Но вывод этого кода (как-то так):
Trying to get lock
Trying to get lock
Trying to get lock
Got lock: Got lock: 10287
Got lock: Got lock: 10287
Enter string to write in file : Trying to get lock
Enter string to wriGot lock: 10287
Got lock: 10287
Got lock: 10287
Enter string to write in file : Trying to get lock
Got lock: 10287
Got lock: Enter string to write in file :
Но когда я удаляю набор полей CLONE_FILES из clone(2), все идет хорошо. Другие потоки клонов будут ожидать блокировки ().
Вывод этого:
Trying to get lock
Got lock: 10311
Trying to get lock
Trying to get lock
Trying to get lock
Trying to get lock
Любые другие альтернативы (с CLONE_FILES)? И почему такого рода поведение?
Новичок в этой области.
1 ответ
Блокировка обеспечивается flock
за процесс, а не за поток.
С http://linux.die.net/man/2/flock (выделено мое):
Вызов flock() может блокироваться, если другой процесс удерживает несовместимую блокировку.
Последующие вызовы flock() для уже заблокированного файла преобразуют существующую блокировку в новый режим блокировки.
Блокировки, созданные функцией flock(), связаны с записью в таблице открытых файлов.
Хотя потоки не упоминаются явно, несколько потоков совместно используют запись в таблице файлов, тогда как несколько процессов - нет. Переходя CLONE_FILES
в clone
заставляет ваши "процессы" делиться таблицами файлов.
Решение может быть позвонить dup
сделать больше файловых дескрипторов. Из документации:
Если процесс использует open(2) (или аналогичный) для получения более одного дескриптора для одного и того же
файл, эти дескрипторы обрабатываются независимо с помощью flock(). Попытка заблокировать файл с помощью одного из этих файловых дескрипторов может быть отклонена блокировкой, которую вызывающий процесс уже установил через другой дескриптор.