2015-12-31 4 views
1

Это неловко, по-видимому, я не (снова?) Что-то основное о разветвление понять ...стадо() не похоже на работу с вилкой()

Я ожидал, что код (под Linux, CentOS 6.3), чтобы напечатать

lock returned 0 
unlock 
lock returned 0 
unlock 

, но это не так, как замки удается сразу:

lock returned 0 
lock returned 0 
unlock 
unlock 

Почему?

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <sys/file.h> 

void main() { 
    int fd = open("lock.txt", O_WRONLY | O_CREAT); 
    int lock_ret; 

    fork(); 

    lock_ret = flock(fd, LOCK_EX); 
    printf("lock returned %d\n", lock_ret); 
    fflush(stdout); 

    sleep(4); 

    printf("unlock\n"); 
    fflush(stdout); 
} 

Если удалить fork() и просто начать два процесса вручную, то все работает, как и ожидалось, один замок успешно, другие блоки и успешно позже.

+0

Возможно, это работает так, как я понимаю из вашего вывода на печать. Один из двух разветвленных процессов получает блокировку ... спит, разблокирует ... В то время как это происходит, второй процесс запуска запускает свою стаю, и он ждет, когда первый процесс разблокируется. Это то, что вы видите в printf(), process_1 запускается (process_2 запускается, но ждет), process_1 спит и заканчивается, затем process_2 запускается и заканчивается. –

+0

Опишите, что случилось. Какая у вас ошибка ? –

+0

@JorgeTorres нет, что вы говорите - это не то, что происходит. Второй процесс _is_not_ ждет. Это проблема. –

ответ

1

На странице flock человек Linux:

Блокировки, созданные паствы() связаны с открытым описанием файла (см разомкнут (2)). Это означает, что дескрипторы дубликатов файлов (созданный, например, fork (2) или dup (2)) ссылается на тот же замок, и эта блокировка может быть изменена или выпущена с использованием любого из этих дескрипторов.

Ожидаемое поведение.

+0

Извините ... Я не понимаю, пожалуйста, помогите мне и объясните больше. Из вашего ответа поведение должно быть таким, как я ожидал, - первой распечаткой выше. Это не так, он печатает второй способ. –

+1

Первый процесс вызывает стадо и получает блокировку. Второй процесс вызывает flock, ядро ​​видит, что блокировка уже сохранена для этого дескриптора файла, вызов сразу же выполняется. Эти два процесса работают над «одним и тем же» файловым дескриптором, это как если бы только один процесс вызывал flock два раза для этого fd. – Mat

+0

Oh ....! «Файловый дескриптор» - это не просто «число», за ним стоит целая скрытая машина. Я понял. Как синхронизировать родительский и дочерний доступ к файлу? –

2

По словам человека паствы:

Блокировки, созданные паствы() связаны с файлом, или, более точно , открытый входной файл таблицы. Это означает, что дубликаты файлов дескрипторы (созданные, например, fork (2) или dup (2)) относятся к одной и той же блокировке , и эта блокировка может быть изменена или выпущена с использованием любого из этих дескрипторов . Кроме того, блокировка освобождается либо с помощью явной операции LOCK_UN на любом из этих дублирующих дескрипторов, либо , когда все такие дескрипторы были закрыты.

Итак, поскольку вы открываете процесс после открытия файла, они имеют одну и ту же блокировку. Это означает, что другой процесс не может стекаться в один и тот же файл, пока оба родителя и родителя не закроют файл.

+0

Итак ...? Я не спрашиваю о другом процессе. Я спрашиваю о ребенке и родителе _only_. –

1

Если вы хотите, чтобы эксклюзивные замки не были сохранены через вилки, вы можете использовать fcntl.

struct flock fd_lock = { F_RDLCK, SEEK_SET, 0, 0, 0 }; 

fcntl(fd, F_SETLK, &fd_lock); // not across fork/exec 
+0

Хорошо, это здорово, но ... как я могу заставить эту вещь блокировать и не прерывать немедленно ни в родителях, ни в детях? –

+1

@MarkGaleck 'F_SETLKW' должен делать то, что вы хотите. – Jason

+0

yessir, СПАСИБО –

2

Там какая-то ласка формулировка в руководстве по эксплуатации flock():

Блокировки, созданная flock() связана с открытой записью таблицы файлов. Это означает, что дубликаты дескрипторов файлов (созданные, например, fork(2) или dup(2)) относятся к одной и той же блокировке, и эта блокировка может быть изменена или выпущена с использованием любого из этих дескрипторов.

Вы можете продемонстрировать это, более тщательно измерив программу, и разумно добавив еще одну вилку.Также неплохо убедиться, что файл создан правильно - при использовании O_CREAT, open() нужен третий аргумент для указания режима файла.

#include <fcntl.h> 
#include <stdio.h> 
#include <sys/file.h> 
#include <sys/stat.h> 
#include <sys/wait.h> 
#include <time.h> 
#include <unistd.h> 

int main(void) 
{ 
    printf("%ld:%d: Before fork 1\n", (long)time(0), (int)getpid()); 
    fork(); 
    printf("%ld:%d: After fork 1\n", (long)time(0), (int)getpid()); 

    int fd = open("lock.txt", O_WRONLY | O_CREAT, 0644); 
    int lock_ret; 

    fork(); 
    printf("%ld:%d: After fork 2\n", (long)time(0), (int)getpid()); 

    lock_ret = flock(fd, LOCK_EX); 
    printf("%ld:%d: lock returned %d\n", (long)time(0), (int)getpid(), lock_ret); 
    fflush(stdout); 

    sleep(4); 

    lock_ret = flock(fd, LOCK_UN); 
    printf("%ld:%d: unlock returned %d\n", (long)time(0), (int)getpid(), lock_ret); 
    fflush(stdout); 
    int corpse; 
    int status; 
    while ((corpse = wait(&status)) != -1) 
     printf("%ld:%d: PID %d died with status 0x%.4X\n", (long)time(0), (int)getpid(), corpse, status); 
    return 0; 
} 

Пример запуска:

1451543977:5731: Before fork 1 
1451543977:5731: After fork 1 
1451543977:5731: After fork 2 
1451543977:5731: lock returned 0 
1451543977:5732: After fork 1 
1451543977:5733: After fork 2 
1451543977:5733: lock returned 0 
1451543977:5732: After fork 2 
1451543977:5734: After fork 2 
1451543981:5731: unlock returned 0 
1451543981:5733: unlock returned 0 
1451543981:5732: lock returned 0 
1451543981:5731: PID 5733 died with status 0x0000 
1451543985:5732: unlock returned 0 
1451543985:5734: lock returned 0 
1451543989:5734: unlock returned 0 
1451543989:5732: PID 5734 died with status 0x0000 
1451543989:5731: PID 5732 died with status 0x0000 

Обратите внимание, как процессы, которые не разделяют один и тот же открытый файл описания блокированы; те, которые используют одно и то же открытое описание файла, не блокируются.

Также обратите внимание, что время штамповки и (особенно) «штамповка ПИД» выход помогает сделать вывод однозначным.

Смежные вопросы