Boost interprocess lock_file does not work between two processes - c++

I am trying to use boost file_lock to control two processes. I have process 1 obtaining a lock and then sleeping:
#include <boost/interprocess/sync/file_lock.hpp>
#include <fstream>
#include <chrono>
#include <thread>
int main()
{
std::string lock_path = "lockfile";
std::ofstream stream(lock_path, std::ios::app);
boost::interprocess::file_lock lock(lock_path.c_str());
if (lock.try_lock())
{
std::this_thread::sleep_for(std::chrono::seconds(30));
}
return 0;
}
while this process is sleeping, I will run a second process which tries to obtain the lock as well.
#include <boost/interprocess/sync/file_lock.hpp>
#include <iostream>
int main()
{
boost::interprocess::file_lock lock("lockfile");
if (lock.try_lock())
{
std::cout << "got here" << std::endl;
}
return 0;
}
I am expecting the cout statement on the second process not to print because the file is already locked by another process but it does print. What am I missing here? is file_lock not supposed to be used this way?

The best explanation I can think of is when your processes accidentally refer to different files. This might occur when
the current working directories are not the same
the processes run in isolated environments altogether (e.g. dockerized)
the file has been deleted/recreated in the meantime (meaning the inode doesn't match, even though the filename does)
Here's a simplified program that can serve as both parties:
Live On Coliru
#include <fstream>
#include <iostream>
#include <thread>
#include <boost/static_assert.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
namespace bip = boost::interprocess;
using namespace std::chrono_literals;
static inline auto constexpr lock_path = "lockfile";
int main() {
bip::file_lock lock(lock_path);
if (lock.try_lock()) {
std::ofstream stream(lock_path, std::ios::app);
std::cout << "got lock" << std::endl;
std::this_thread::sleep_for(2s);
}
std::cout << "bye" << std::endl;
}
Local demo:

Related

Linux c++: Will blocked threads prevent app process terminating after returning from main function?

This problem is duplicate, but I am still confused about how os will resolve child threads after returning from main function.
Most pepole said that os will invoke exit_group() or exit() to terminate all child threads.
However, I found blocked threads will prevent process terminating.Reading up the documention of linux man page, I didn't find the special works for blocked threads.
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <unistd.h>
using namespace std;
mutex m;
condition_variable cv;
int main() {
auto t = thread([]() {
unique_lock<mutex> lock(m);
cv.wait(lock);
});
t.detach();
sleep(1);
cout << "hello" << endl;
return 0;
}
Running above code will print "hello" and then always stuck in blocking.
If simulate the behaviors os to do, directly invoke _exit(2) (be equivalent to exit_group()) in main function, process will terminate normally.
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <unistd.h>
using namespace std;
mutex m;
condition_variable cv;
int main() {
auto t = thread([]() {
unique_lock<mutex> lock(m);
cv.wait(lock);
});
t.detach();
sleep(1);
cout << "hello" << endl;
exit(0);
return 0;
}
If use exit() instead of _exit(2), process will be stuck after printing "hello".
So what exactly did os do after returning for main funcion? Will blocked threads prevent process terminating?
The following code will work normally.
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <unistd.h>
using namespace std;
mutex m;
condition_variable cv;
int main() {
auto t = thread([]() {
unique_lock<mutex> lock(m);
cv.wait(lock);
});
t.detach();
auto t2 = thread([](){
unique_lock<mutex> lock(m);
cv.wait_for(lock,chrono::seconds(2));
cv.notify_all();
});
t2.detach();
sleep(1);
cout << "hello" << endl;
return 0;
}

Delay an output in C++ using 'ctime' library

How do I delay an output in C++? I tried searching for similar questions, but I didn't find any solution which makes use of the 'ctime' library. Help please.
Have a look at this answer.
You could use std::this_thread::sleep_for(std::chrono::milliseconds(x));
For example:
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
int x{3000};
std::cout << "Start waiting\n";
std::this_thread::sleep_for(std::chrono::milliseconds(x));
std::cout << "Done waiting\n";
return 0;
}

Why does this C++ program take so long to finish if you run it as a root?

I want to clear L1, L2 and L3 cache 50 times by executing the following code. However it becomes very slow if I run it by typing sudo ./a.out. On the other hand, if I just write ./a.out it will finish executing almost instantly. I do not understand the reason for this since I am not getting any errors in the terminal.
#include <iostream>
#include <cstdlib>
#include <vector>
#include <fstream>
#include <unistd.h>
using namespace std;
void clear_cache(){
sync();
std::ofstream ofs("/proc/sys/vm/drop_caches");
ofs << "3" << std::endl;
sync();
}
int main() {
for(int i = 0; i < 50; i++)
clear_cache();
return 0;
};
You don't have enough permissions to write to this file as a regular user:
-rw-r--r-- 1 root root 0 Feb 11 15:56 /proc/sys/vm/drop_caches
Only version run as a privileged user works, hence it takes longer. The reason you're not getting any errors is that you're not checking any errors.
Here's the most simple check:
#include <iostream>
#include <cstdlib>
#include <vector>
#include <fstream>
#include <unistd.h>
using namespace std;
void clear_cache(){
sync();
std::ofstream ofs("/proc/sys/vm/drop_caches");
if (!ofs)
{
std::cout << "could not open file" << std::endl;
exit(EXIT_FAILURE);
}
ofs << "3" << std::endl;
sync();
}
int main() {
for(int i = 0; i < 50; i++)
clear_cache();
return 0;
};
Output:
% ./a.out
could not open file

Concurrency memory corruption using Boost 1.55 Thread and Filesystem (Visual Studio 2013)

I have the following code:
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <thread>
#define BOOST_THREAD_DYN_LINK
#include "boost/filesystem.hpp"
#include "boost/thread/thread.hpp"
using namespace std;
void testEx(std::string & name){
while (1){
boost::filesystem::path perc(name);
if (boost::filesystem::exists(perc))
cout << "yes" << endl;
}
}
int main(){
std::string name = "c:\\text.txt";
vector<boost::thread> pool;
for (int i = 0; i < 10;i++)
pool.emplace_back(testEx, name);
while (1){
std::ofstream out(name, std::ios_base::out | std::ios_base::app);
out << "a" << std::endl;
out.close();
}
for (auto & t : pool)
t.join();
}
The main thread is writing a file. With child threads i check if the file exists. The program often crashes with memory corruption in the line where i create a boost::filesystem::path instance.
If i use std::thread instead of boost::thread the program works fine.
Is there anything i can do to get this program work with boost::thread (lots of legacy code). Why is this happening?
By now i resolved by linking dynamically boost::filesystem too
#define BOOST_FILESYSTEM_DYN_LINK
just a workaround anyway

When boost library "interprocess" defines a named_mutex do those named_mutexes work properly between different processes, or only with threads?

I think I must be assuming something from the name boost::interprocess that is not true.
The documents repeat that named_mutex is global here.
I am unable to make it work though. Two copies of the same executable should be run at the same time, and I expect that a named mutex in a library named boost::interprocess might actually BLOCK sometimes. It doesn't. It also doesn't prevent data file corruption in the code below.
Here's some code from the boost docs:
#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;
Here's what I did to it so I could prove to myself the mutex was doing something:
#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;
}
Console Output:
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...
Also, the demo writes to a file, which if you run two copies of the program will be missing some data.
I expect that if I delete file_name and run two copies of the program, I should get interleaved writes to file_name containing 100 rows from each instance.
(Note, that the demo code is clearly not using an ofstream in append mode, instead it simply rewrites the file each time this program runs, so if we wanted a demo to show two processes writing to a file, I'm aware of that reason why it wouldn't work, but what I did expect is for the above code to be a feasible demonstration of mutual exclusion, which it is not. Also calls to a very handy and aptly named ofstream::flush() method could have been included, and weren't.)
Using Boost 1.53 on Visual C++ 2008
It turns out that Boost is a wonderful library, and it code examples interspersed in the documentation may sometimes be broken. At least the one for boost::interprocess::named_mutex in the docs is not functional on Windows systems.
*Always deleting a mutex as part of the demo code causes the mutex to not function. *
That should be commented in the demo code at the very least. It fails to pass the "principle of least amazement", although I wondered why it was there, I thought it must be idiomatic and necessary, it's idiotic and unnecessary, in actual fact. Or if it's necessary it's an example of what Joel Spolsky would call a leaky abstraction. If mutexes are really filesystem points under C:\ProgramData in Windows I sure don't want to know about it, or know that turds get left behind that will break the abstraction if I don't detect that case and clean it up. (Sure smells like posix friendly semantics for mutexes in Boost have caused them to use a posix-style implementation instead of going to Win32 API directly and implementing a simple mutex that has no filesystem turds.)
Here's a working demo:
#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;
}
I would love critques and edits on this answer, so that people will have a working demo of using this named mutex .
To use the demo:
- Build it and run two copies of it. Pass a parameter in so you can see which instance wrote which lines (start myexename ABC and start myexename DEF from a command prompt in windows)
- If it's your second run, delete any stray output named "file_name" if you don't want the second run appended to the first.