2013-03-09 2 views
2

나는 사실이 아닌 boost::interprocess이라는 이름에서 뭔가를 추측해야한다고 생각합니다. named_mutex은 전체 문서가 here입니다.boost 라이브러리 "interprocess"가 named_mutex를 정의 할 때, named_mutexes는 다른 프로세스간에 또는 스레드와 만 제대로 작동합니까?

그래도 작동하지 않습니다. 동일한 실행 파일의 두 복사본을 동시에 실행해야하며 라이브러리의 명명 된 뮤텍스가 실제로는 때때로 BLOCK이 될 수도 있습니다. 그렇지 않습니다. 또한 아래 코드에서 데이터 파일 손상을 방지하지 않습니다.

#include <windows.h> 
#include <boost/interprocess/sync/interprocess_mutex.hpp> 
#include <boost/lambda/lambda.hpp> 
#include <boost/interprocess/sync/scoped_lock.hpp> 
#include <boost/interprocess/sync/named_mutex.hpp> 
#include <iostream> 
#include <iterator> 
#include <algorithm> 
#include <fstream> 
#include <iostream> 
#include <cstdio> 


int main (int argc, char *argv[]) 
{ 
    srand((unsigned) time(NULL)); 

    using namespace boost::interprocess; 
    try{ 
     /* 
     struct file_remove 
     { 
     file_remove() { std::remove("file_name"); } 
     ~file_remove(){ std::remove("file_name"); } 
     } file_remover; 
     */ 

     struct mutex_remove 
     { 
     mutex_remove() { named_mutex::remove("fstream_named_mutex"); } 
     ~mutex_remove(){ named_mutex::remove("fstream_named_mutex"); } 
     } remover; 

     //Open or create the named mutex 
     named_mutex mutex(open_or_create, "fstream_named_mutex"); 

     std::ofstream file("file_name"); 

     for(int i = 0; i < 100; ++i){ 

     //Do some operations... 

     //Write to file atomically 
     DWORD n1,n2; 
     n1 = GetTickCount(); 
     scoped_lock<named_mutex> lock(mutex); 
     n2 = GetTickCount(); 
     std::cout << "took " << (n2-n1) << " msec to acquire mutex"; 
     int randomtime = rand()%10; 
     if (randomtime<1) 
      randomtime = 1; 
     Sleep(randomtime*100); 
     std::cout << " ... writing...\n"; 
     if (argc>1) 
      file << argv[1]; 
     else 
      file << "SOMETHING"; 
     file << " This is iteration #" << i; 
     file << std::endl; 
     file.flush(); // added in case this explains the corruption, it does not. 
     } 
    } 
    catch(interprocess_exception &ex){ 
     std::cout << "ERROR " << ex.what() << std::endl; 
     return 1; 
    } 
    return 0; 
} 

콘솔 출력 :

여기에 내가 뮤텍스 뭔가를하고 있던 자신에게 증명할 수 있는지 내가 한 짓입니다

#include <boost/interprocess/sync/scoped_lock.hpp> 
#include <boost/interprocess/sync/named_mutex.hpp> 
#include <fstream> 
#include <iostream> 
#include <cstdio> 


int main() 
{ 
    using namespace boost::interprocess; 
    try{ 
     struct file_remove 
     { 
     file_remove() { std::remove("file_name"); } 
     ~file_remove(){ std::remove("file_name"); } 
     } file_remover; 
     struct mutex_remove 
     { 
     mutex_remove() { named_mutex::remove("fstream_named_mutex"); } 
     ~mutex_remove(){ named_mutex::remove("fstream_named_mutex"); } 
     } remover; 

     //Open or create the named mutex 
     named_mutex mutex(open_or_create, "fstream_named_mutex"); 

     std::ofstream file("file_name"); 

     for(int i = 0; i < 10; ++i){ 

     //Do some operations... 

     //Write to file atomically 
     scoped_lock<named_mutex> lock(mutex); 
     file << "Process name, "; 
     file << "This is iteration #" << i; 
     file << std::endl; 
     } 
    } 
    catch(interprocess_exception &ex){ 
     std::cout << ex.what() << std::endl; 
     return 1; 
    } 
    return 0; 

: 여기

부스트 문서에서 일부 코드입니다
took 0 msec to acquire mutex ... writing... 
took 0 msec to acquire mutex ... writing... 
took 0 msec to acquire mutex ... writing... 
took 0 msec to acquire mutex ... writing... 

데모는 파일에 기록합니다. 프로그램의 두 복사본을 실행하면 일부 데이터가 누락됩니다.

file_name을 삭제하고 프로그램 복사본을 두 개 실행하면 각 인스턴스에서 100 행을 포함하는 file_name으로 인터리브 쓰기를해야합니다.

(데모 코드는 추가 모드에서 분명히 ofstream을 사용하지 않고이 프로그램을 실행할 때마다 파일을 간단히 다시 작성하므로 데모에서 두 개의 프로세스가 파일에 쓰는 것을 보여주고 싶다면, 그 이유가 작동하지 않는 이유를 알고 있지만 위의 코드는 위의 코드가 상호 배제의 실현 가능한 데모가 될 것으로 기대하고 있습니다. 매우 편리하고 적절하게 명명 된 ofstream::flush() 메서드 호출은 포함되어 있으며 없었다.) 비주얼 C에 부스트 1.53를 사용

는 ++ 2008

답변

1

이 부스트가 wond임을 밝혀 오류가있는 라이브러리 및 문서에 산재 된 코드 예제가 때때로 손상 될 수 있습니다. Windows 시스템에서는 docs에있는 boost::interprocess::named_mutex에 대한 코드가 작동하지 않습니다.

* 데모 코드의 일부로 항상 뮤텍스를 삭제하면 뮤텍스가 작동하지 않습니다. *

적어도 데모 코드에서 주석 처리되어야합니다. 그것이 왜 그곳에 있었는지 궁금해 했더라도 그것은 "놀랍지 않은 원칙"을 넘어서지 못했습니다. 나는 그것이 관용적이고 필요한 것이어야한다고 생각했습니다. 그것은 실제로 바보 같고 불필요합니다. 또는 필요한 경우 Joel Spolsky가 새는 추상화라고 부르는 예입니다. 뮤텍스가 실제로 Windows에서 C:\ProgramData 아래의 파일 시스템 포인트 인 경우 확실하지 않거나 그 케이스를 감지하지 못하고 정리하지 않으면 텅 빈 코드가 추상화를 깨뜨릴 수 있습니다. (Boost의 뮤텍스에 대한 posix 친숙한 의미론과 같은 냄새는 Win32 API로 직접 가서 파일 시스템이없는 간단한 뮤텍스를 구현하는 대신 posix 스타일 구현을 사용하게 만든다.)

다음은 작업 데모이다 :

#include <windows.h> 
#include <boost/interprocess/sync/interprocess_mutex.hpp> 
#include <boost/lambda/lambda.hpp> 
#include <iostream> 
#include <iterator> 
#include <algorithm> 

#include <boost/interprocess/sync/scoped_lock.hpp> 
#include <boost/interprocess/sync/named_mutex.hpp> 
#include <fstream> 
#include <iostream> 
#include <cstdio> 
#include <windows.h> 

int main (int argc, char *argv[]) 
{ 
    srand((unsigned) time(NULL)); 

    using namespace boost::interprocess; 
    try{ 
     /* 
     // UNCOMMENT THIS IF YOU WANT TO MAKE THIS DEMO IMPOSSIBLE TO USE TO DEMO ANYTHING 

     struct file_remove 
     { 
     file_remove() { std::remove("file_name"); } 
     ~file_remove(){ std::remove("file_name"); } 
     } file_remover; 

     // UNCOMMENT THIS IF YOU WANT TO BREAK THIS DEMO HORRIBLY: 

     struct mutex_remove 
     { 
     mutex_remove() { named_mutex::remove("fstream_named_mutex"); } 
     ~mutex_remove(){ named_mutex::remove("fstream_named_mutex"); } 
     } remover; 
     */ 

     //Open or create the named mutex 
     named_mutex mutex(open_or_create, "fstream_named_mutex"); 

     std::ofstream file("file_name", std::ios_base::app); 
     int randomtime = 0; 
     for(int i = 0; i < 100; ++i){ 

     //Do some operations... 

     //Write to file atomically 
     DWORD n1,n2; 
     n1 = GetTickCount(); 

     { 
     scoped_lock<named_mutex> lock(mutex); 
     n2 = GetTickCount(); 
     std::cout << "took " << (n2-n1) << " msec to acquire mutex"; 

     randomtime = rand()%10; 
     if (randomtime<1) 
      randomtime = 1; 

     std::cout << " ... writing...\n"; 
     if (argc>1) 
      file << argv[1]; 
     else 
      file << "SOMETHING"; 
     file << "..."; 
     Sleep(randomtime*100); 
     file << " This is iteration #" << i; 
     file << std::endl; 
     file.flush(); 
     } 
     Sleep(randomtime*100); // let the other guy in. 
     } 
    } 
    catch(interprocess_exception &ex){ 
     std::cout << "ERROR " << ex.what() << std::endl; 
     return 1; 
    } 
    return 0; 
} 

사람들이이 이름 지정된 뮤텍스를 사용하는 데모를 제공 할 수 있도록이 답변에 대한 비평과 편집을 좋아합니다.

데모를 사용하려면
- 빌드하고 두 개의 사본을 실행하십시오. 어떤 인스턴스가 어떤 행을 썼는지 볼 수 있도록 매개 변수를 전달하십시오 (Windows의 명령 프롬프트에서 start myexename ABCstart myexename DEF). - 두 번째 실행 인 경우 두 번째 실행을 추가하지 않으려면 "file_name"이라는 누락 된 출력을 삭제하십시오 첫 번째.

enter image description here

+0

나는의 아무 생각이 무엇을 (그것은 아무것도 전혀 않는 경우)하지만, 원래의 샘플에서 당신은 '(무효) 제거 누락 하였다'(named_mutex 뮤텍스'전에' . –

+0

두 번 확인해 보겠습니다. –

+0

나는 '제거제'라는 생각은 새로운 뮤텍스를 만들기 전에 이전 실행 상태로 남아있는 가능한 뮤텍스를 제거한 다음 마지막에 제거한다고 말합니다. 일단 제거제가 꺼지면 (void) 제거기 란 무엇인지 모르겠지만 컴파일러가'제거 자 '를 최적화하지 못하게하는 방법 일 수도 있고'file_remover'와 동일하게 할 수도 있습니다. –