2016-10-20 3 views
2

FileLocker_wo.h는 파일

#include <string> 

namespace Utils 
{ 
     namespace FileLocker 
     { 
       bool lock_file(std::string aFileName, int& aFileDescriptor); 

       bool unlock_file(int& aFileDescriptor); 

       bool is_file_locked(std::string aFileName); 
     }; 
} 

FileLocker_wo.cpp

namespace Utils 
{ 
     namespace FileLocker 
     { 
       bool lock_file(std::string aFileName, int& aFileDescriptor) 
       { 
         aFileDescriptor = open(aFileName.c_str(), O_RDWR); 

         if (aFileDescriptor != -1) 
         { 
           if (lockf(aFileDescriptor, F_TLOCK, 0) == 0) 
           { 
             return true; 
           } 

           std::cout << strerror(errno) << std::endl; 
         } 

         return false; 
       } 

       bool unlock_file(int& aFileDescriptor) 
       { 
         if (lockf(aFileDescriptor, F_ULOCK, 0) == 0) 
         { 
           std::cout << "unloced file" << std::endl; 
           close(aFileDescriptor); 
           return true; 
         } 
         close(aFileDescriptor); 
         return false; 
       } 

       bool is_file_locked(std::string aFileName) 
       { 
         int file_descriptor = open(aFileName.c_str(), O_RDWR); 

         if (file_descriptor != -1) 
         { 
           int ret = lockf(file_descriptor, F_TEST, 0); 

           if (ret == -1 && (errno == EACCES || errno == EAGAIN)) 
           { 
             std::cout << "locked by another process" << std::endl; 
             close(file_descriptor); 
             return true; 
           } 

           if (ret != 0) 
           { 
            std::cout << "return value is " << ret << " " << strerror(errno) << std::endl; 
           } 

         } 
         close(file_descriptor); 
         return false; 
       } 
     } 
} 

p1.cpp

#include <iostream> 
#include <fstream> 

#include "FileLocker_wo.h" 


int main() 
{ 

     int fd = -1; 
     if (Utils::FileLocker::lock_file("hello.txt", fd)) 
     { 
       std::ofstream out("hello.txt"); 
       out << "hello ding dong" << std::endl; 
       out.close(); 

       std::cout << "locked" << std::endl; 
       sleep(5); 
       if (Utils::FileLocker::unlock_file(fd)) 
       { 
         std::cout << "unlocked" << std::endl; 
       } 
     } 

     return 0; 
} 

p2.cpp

#include "FileLocker_wo.h" 
#include <iostream> 
#include <fstream> 

int main() 
{ 
     int max_trys = 2; 
     int trys = 0; 
     bool is_locked = false; 

     do 
     { 
       is_locked = Utils::FileLocker::is_file_locked("hello.txt"); 

       if (!is_locked) 
       { 
         std::cout << "not locked" << std::endl; 
         break; 
       } 

       std::cout << "locked" << std::endl; 

       sleep(1); 
       ++trys; 
     } 
     while(trys < max_trys); 

     if (!is_locked) 
     { 
       std::string s; 
       std::ifstream in("hello.txt"); 
       while(getline(in,s)) 
       { 
         std::cout << "s is " << s << std::endl; 
       } 
     } 

     return 0; 
} 
에 잠금을 획득 할 수 없습니다

한 프로세스에서 파일 잠금을 얻고 lockf (p1.cpp, p2.cpp)를 사용하여 다른 프로세스에서 해당 파일에 대한 잠금이 있는지 확인하려고합니다.

p1.cpp에서 hello.txt 파일을 잠그고 5 초 동안 기다리고 있습니다. 한편 p2.cpp를 시작하고 다른 프로세스에 의해 잠금이 있는지를 확인하지만 항상 잠금이없는 경우> 지난 2 시간 동안이 문제에 봉착했습니다.

아무도이 문제가 무엇인지 잘못 알 수 있습니까?

+3

'lockf'가 방금 0이 아닌 값을 반환 한 * 곳에 * strerror (errno)를 인쇄하도록 프로그램을 변경하십시오. 그들을 다시 실행하십시오. 그들이 무엇을 인쇄하는지 알려주십시오. – zwol

+1

0이 아닌 값을 반환하지 않습니다. 로그는 제자리에 있지만 항상 반환되기 때문에 인쇄되지 않습니다. 이제 로그에 대한 변경 사항을 코드로 편집하십시오. – naren

+1

파일을 열어 둘 필요가 없도록 일종의 객체를 만들어야하지 않습니까?'is_file_locked()'에서는 파일 디스크립터를 열지 만 닫지 않습니다. 당신은 파일 기술자를 다 써 버릴 것이다. 'lock_file()'이나'unlock_file()'에서 파일 디스크립터를 닫지는 않지만 파일을 닫을 때 락커에 onus를 남긴다. 소멸자와 RAII는 삶을 더 간단하게 만들 것입니다. –

답변

3

당신은 POSIX 파일 잠금에서 가장 까다로운 설계 오류 중 하나를 넘어 섰습니다. 프로세스가 파일을 참조하는 파일 기술자를 닫을 경우,

  • : 당신은 단지 lockf manpage 아닌 fcntl manpage을 읽을 수 있기 때문에 당신은 아마 그래서 여기 fcntl 맨의 중요한 비트입니다, 이것에 대해 알지 못했다 잠금을 얻은 파일 설명자에 관계없이 해당 파일에 대한 프로세스의 모든 잠금이 해제됩니다. 이 의미

"는 out 다른 OS 레벨은 out.close(), 불구하고 호출 할 때

if (Utils::FileLocker::lock_file("hello.txt", fd)) 
    { 
      std::ofstream out("hello.txt"); 
      out << "hello ding dong" << std::endl; 
      out.close(); 

당신이 파일에 잠금을 잃게 코드의이 비트에서, 열린 파일 설명 "lock_file에서 사용한 것보다! 이 파일에 당신이 open() 전화 있는지 확인해야 안전하게 POSIX 잠금을 사용하려면

는 한 번만 프로세스 당 를 고정 할, 당신은 파일 기술자를 복제해서는 안, 그리고 때 당신은 단지 그것을 다시 닫아야합니다 자물쇠를 떨어 뜨릴 준비가되었습니다. 파일 설명자에서 iostreams 객체를 생성하거나 iostreams 객체에서 파일 디스크립터를 추출하는 방법 (전송 불가능한 확장자 사용)이 없기 때문에 최소한의 저항 경로는 OS 레벨 I/O 프리미티브 (open, close, read, write, fcntl, lseek, ftruncate)는 POSIX 잠금 장치를 적용해야 할 파일과.

+0

위대한, 그 문제를 해결, 내가 upvote 싶었지만, 난 할 수 없어 ... – naren

+0

나는이 컨텍스트에서 다른 질문을 가지고, (fd)는 ofstream에 의해 사용되는 모든 설명자를 닫을 것입니다 같은 파일을 열려면 ofstream.close())를 호출하지 않았습니까? – naren

+0

아니요, ofstream에는 자체 "열린 파일 설명"이 있으며 닫기 (fd)는 영향을 미치지 않습니다. 그러나 잠금은 열린 파일이 아닌 * process *와 연관되어 있기 때문에 잠금은 ofstream.close() 및 close (fd)의 * first *에서 삭제됩니다. – zwol