3

Abstract

I present a small example of code reproducing a very strange bug I have in my software. It creates 3 named semaphores with Boost, and waits for each in a single thread. This works. But if I change the names of the semaphores (by adding a given prefix), it doesn't: the 3th semaphore waits for infinite time with no reason.

Details (source code and behavior)

#include <string>
#include <vector>
#include <iostream>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
#include <boost/interprocess/sync/named_semaphore.hpp>

struct Lock
{
    std::string name;
    unsigned int count;
    Lock(const std::string& name_, unsigned int count_) : name(name_), count(count_) {}
};

int main()
{
    std::vector<Lock> locks;
    locks.push_back(Lock("Sleep1", 1));
    locks.push_back(Lock("Hello", 1));
    locks.push_back(Lock("Sleep2", 1));

    for(std::size_t i = 0; i < locks.size(); ++i)
    {
        {
            const std::string sem_name = locks[i].name;
            const unsigned int sem_count = locks[i].count;
            std::cout << "Open or Create semaphore (" << sem_name << ", " << sem_count << ")" << std::endl;
            boost::interprocess::named_semaphore semaphore(boost::interprocess::open_or_create, sem_name.c_str(), sem_count);
            std::cout << "Wait..." << std::flush;
            semaphore.wait();
            std::cout << " DONE" << std::endl;
        }
        boost::this_thread::sleep(boost::posix_time::seconds(5));
        {
            const std::string sem_name = locks[i].name;
            std::cout << "Open semaphore (" << sem_name << ")" << std::endl;
            boost::interprocess::named_semaphore semaphore(boost::interprocess::open_only, sem_name.c_str());
            std::cout << "Post..." << std::flush;
            semaphore.post();
            std::cout << " DONE" << std::endl;
        }
    }

    return 0;
}

Executing this example, I get the following (expected) output:

> ./sem
Open or Create semaphore (Sleep1, 1)
Wait... DONE
Open semaphore (Sleep1)
Post... DONE
Open or Create semaphore (Hello, 1)
Wait... DONE
Open semaphore (Hello)
Post... DONE
Open or Create semaphore (Sleep2, 1)
Wait... DONE
Open semaphore (Sleep2)
Post... DONE

If I replace the line defining the names of the semaphores by the following:

std::vector<Lock> locks;
locks.push_back(Lock("CHAIN_EVALUATOR_Sleep1", 1));
locks.push_back(Lock("CHAIN_EVALUATOR_Hello", 1));
locks.push_back(Lock("CHAIN_EVALUATOR_Sleep2", 1));

the execution doesn't terminate with the following output:

Open or Create semaphore (CHAIN_EVALUATOR_Sleep1, 1)
Wait... DONE
Open semaphore (CHAIN_EVALUATOR_Sleep1)
Post... DONE
Open or Create semaphore (CHAIN_EVALUATOR_Hello, 1)
Wait... DONE
Open semaphore (CHAIN_EVALUATOR_Hello)
Post... DONE
Open or Create semaphore (CHAIN_EVALUATOR_Sleep2, 1)
Wait...

Note the strange choice for the new names. Actually, it fails with that. It doesn't fail with FOO_BAR_FOO_BAR_Sleep1, nor FOOBAR_FOOBAR_Sleep1. It looks so strange, I suppose I don't use it correctly and I'm in a random behavior...

Configuration

  • Linux openSUSE 42.1
  • GCC 4.8.5
  • Boost 1.64.0 (including Boost.Python with python 2.7.9)

Compilation line

g++ test_semaphore.cpp -o sem \
-I /softs/boost/1.64.0/python/2.7.9/64/gcc/4.8.5/include \
/softs/boost/1.64.0/python/2.7.9/64/gcc/4.8.5/lib/libboost_date_time-mt.a \
/softs/boost/1.64.0/python/2.7.9/64/gcc/4.8.5/lib/libboost_thread-mt.a \
/softs/boost/1.64.0/python/2.7.9/64/gcc/4.8.5/lib/libboost_system-mt.a \
-l pthread

Note : I don't use C++11 for compatibility reason.

Caduchon
  • 4,574
  • 4
  • 26
  • 67
  • 2
    Try calling `named_semaphore::remove` before creating. Since you pass `open_or_create` there might be existing named semaphore with the specified name (from previous interrupted launch maybe?). – user7860670 Sep 18 '17 at 10:18
  • @VTT indeed, it's the cause of the bug. I can generate it with the name I want by killing my executable at the right moment. Please add an answer, I will accept it. Now my problem is control the first call to remove before. – Caduchon Sep 18 '17 at 10:27

1 Answers1

2

Named semaphors in boost are implying Kernel or Filesystem persistence so when you pass open_or_create there might be existing named semaphore with the specified name (from previous interrupted launch maybe?) and in this case sem_count will be ignored and semaphore will be in whatever state it has been left in. Try calling named_semaphore::remove before creating or pass create_only flag.

user7860670
  • 35,849
  • 4
  • 58
  • 84