Find the answer to your Linux question:
Results 1 to 5 of 5
Hello! I'm a newbie at programming in Linux. I'm trying to create a semaphore shared amongst multiple processes for testing purposes. I want to see if I can create something ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Jan 2007
    Posts
    5

    destruction of a shared semaphore


    Hello!

    I'm a newbie at programming in Linux.

    I'm trying to create a semaphore shared amongst multiple processes for testing purposes. I want to see if I can create something similar to Named Mutexes and Named Events that are available in Windows.

    I created a small class CNamedSemaphore. The class exposes 2 methods, Lock and Unlock. Lock decreases the semaphore count and Unlock increases it. If 2 processes try to Lock the same shared semaphore, the second one has to wait until the first one unlocks it and so on. Everything works well. If I use IPCS, I can see my shared semaphore.

    The problem I'm facing is when the destructor of my class is called, it calls
    semctl( m_shr_sem, 0, IPC_RMID );
    The call destroys it completely. After running IPCS, I don't see it anymore even if I still have multiple processes running with a reference to that semaphore.
    I assumed that there was some kind of reference count on it and only the last call would really destroy it but it is not the case. I looked inside the structures but I didn't see anything.

    I can easily create shared memory to store my own count but it is an overhead I'd like to avoid if possible. Am I missing something? Is there a better way to do this.

    Here is the code for my class:

    Code:
    class CNamedSemaphore
    {
    public:
    	CNamedSemaphore(long in_lValue, int *out_piReturn);
    
    	~CNamedSemaphore();
    	
    	int CreateNamedSemaphore(long in_lValue);
    	int	Lock();
    	int	TryLock();	
    	int	Unlock();
    private:
    	int	       		m_shr_sem;
    	key_t 	       	m_semKey;
    	struct sembuf   m_semBuf;
    	int				m_flag;
    };
    
    #include "cnamedsemaphore.h"
    
     #include <sys/mman.h>
    
    union semun {
    	int val;		/* value for SETVAL */
    	struct semid_ds *buf;	/* buffer for IPC_STAT & IPC_SET */
    	unsigned short *array;	/* array for GETALL & SETALL */
    	struct seminfo *__buf;	/* buffer for IPC_INFO */
    	void *__pad;
    };
    
    CNamedSemaphore::CNamedSemaphore(long in_lValue, int *out_piReturn)
    : 
    m_shr_sem(-1),
    m_semKey(0)
    {
    	*out_piReturn = CreateNamedSemaphore(in_lValue);
    }
    
    CNamedSemaphore::~CNamedSemaphore()
    {
    	if (m_shr_sem < 0)
    	{
    		return;
    	}
    	semctl( m_shr_sem, 0, IPC_RMID );
    }
    	
    int CNamedSemaphore::CreateNamedSemaphore(long in_lValue)
    {
    	if (m_shr_sem != -1)
    		return -1;
    	
    	m_semKey = (key_t) in_lValue;
    	
    	m_flag = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
    	
    	m_shr_sem  = (int) semget( m_semKey, 1, m_flag );
    	
    	if (m_shr_sem < 0)
    	{
    		m_flag |= IPC_CREAT;
    		
    		m_shr_sem  = (int) semget( m_semKey, 1, m_flag );
    		
    		if (m_shr_sem < 0)
    		{
    			return -1;
    		}
    	}
    	
    	if (m_flag & IPC_CREAT)
    	{
    		union semun      arg;
    	
    		arg.val = 1;
    		if (semctl(m_shr_sem, 0, SETVAL, arg) == -1)
    		{
    			return -1;
    		}
    	}
    
    	return 0;
    }
    
    
    int	CNamedSemaphore::Lock()
    {
    	if (m_shr_sem < 0)
    	{
    		return -1;
    	}
    
    	m_semBuf.sem_num = 0;
    	m_semBuf.sem_op = -1;
    	m_semBuf.sem_flg = SEM_UNDO;
    	if (semop(m_shr_sem, &m_semBuf, 1) != 0)
    		return -1;
    
    	return 0;
    }
    
    int	CNamedSemaphore::TryLock()
    {
    	if (m_shr_sem < 0)
    	{
    		return -1;
    	}
    
    	if (m_shr_sem < 0)
    	{
    		return -1;
    	}
    
    	int	iReturn = 0;
    	m_semBuf.sem_num = 0;
    	m_semBuf.sem_op = -1;
    	m_semBuf.sem_flg = SEM_UNDO | IPC_NOWAIT;
    	errno = 0;
    	iReturn = semop(m_shr_sem, &m_semBuf, 1);
    	if (iReturn == -1)
    	{
    		if (errno == EAGAIN)
    		{
    			return -1;
    		}
    	}
    	return 0;
    }
    
    int	CNamedSemaphore::Unlock()
    {
    	if (m_shr_sem < 0)
    	{
    		return -1;
    	}
    
    	m_semBuf.sem_num = 0;
    	m_semBuf.sem_op  = 1;
    	m_semBuf.sem_flg = SEM_UNDO;
    	
    	if (semop(m_shr_sem, &m_semBuf, 1) != 0)
    		return -1;
    
    	return 0;
    }
    In the app, I would use

    Code:
        int iReturn;
        pNamedSemaphore = (CNamedSemaphore *) new CNamedSemaphore(1000, &iReturn);
    
        // Other parts of the code
        /* Lock button was pressed */
        pNamedSemaphore->Lock();
    
        // Other parts of the code
        /*Unlock button was pressed */
        pNamedSemaphore->Unlock();
    
        // Other parts of the code
        /* Close button was pressed */
        delete pNamedSemaphore;
    Thank you!

  2. #2
    Just Joined!
    Join Date
    Feb 2007
    Posts
    1
    You're stuck.

    There's no automatic reference count mechanism for System V type semaphores.

    Sure, you can use shared memory to keep your own reference count of the semaphore. But be sure to use a semaphore to protect reading and writing this reference count. You don't want two processes modifying it at the same time.

    I rarely recommend this because debugging can be a royal pain, but have you considered using pthreads?

  3. #3
    Just Joined!
    Join Date
    Jan 2007
    Posts
    5
    Thank you for your reply!

    I am experimenting with pthreads, pthread_mutex_t and sem_t too. They are a requirement of our model.

    But because of our architecture, I may need a monitoring app, hence the need to also share data between 2 processes and protect the access to that data.

    I'm investigating what is possible and what is not since we are trying to reuse some of our Windows code to minimize the time to port to Linux.

    Obviously, I will investigate pipes and message queues. Time is a constraint but the main constraint is that the software works

    Thx!

    G.

  4. $spacer_open
    $spacer_close
  5. #4
    Just Joined!
    Join Date
    Jan 2007
    Posts
    5
    On Linuxquestions.org, it was suggested that I create 2 semaphores at once.
    I modified my class to create a semaphore set of 2 semaphores instead of only 1
    semget(m_semKey, 2, flag);

    It seems to be working... Cool!

    Here's my modified class

    Code:
    #include "cnamedsemaphore.h"
    
     #include <sys/mman.h>
    
    union semun {
    	int val;			/* value for SETVAL */
    	struct semid_ds *buf;	/* buffer for IPC_STAT & IPC_SET */
    	unsigned short *array;	/* array for GETALL & SETALL */
    	struct seminfo *__buf;	/* buffer for IPC_INFO */
    	void *__pad;
    };
    
    CNamedSemaphore::CNamedSemaphore(long in_lValue, int *out_piReturn)
    : 
    m_shr_sem(-1),
    m_semKey(0)
    {
    	*out_piReturn = CreateNamedSemaphore(in_lValue);
    }
    
    CNamedSemaphore::~CNamedSemaphore()
    {
    	if (m_shr_sem < 0)
    	{
    		return;
    	}
    	union semun      arg;
    	Lock();
    	arg.val = semctl(m_shr_sem, 1, GETVAL);
    	//check for > 0???
    	assert(arg.val);
    	// cout doesn't work well with threads
    	fprintf(stdout, "CNamedSemaphore::~CNamedSemaphore count=%d\n", arg.val);
    	arg.val--;
    	if (semctl(m_shr_sem, 1, SETVAL, arg) == -1)
    	{
    		arg.val = 0;
    	}
    	Unlock();
    	fprintf(stdout, "CNamedSemaphore::~CNamedSemaphore count=%d\n", arg.val);
    	if (arg.val <= 0)
    	{
    		semctl( m_shr_sem, 0, IPC_RMID );
    	}
    }
    	
    int CNamedSemaphore::CreateNamedSemaphore(long in_lValue)
    {
    	if (m_shr_sem != -1)
    		return -1;
    	
    	int				flag;
    	m_semKey = (key_t) in_lValue;
    	
    	flag = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
    	
    	m_shr_sem  = (int) semget( m_semKey, 2, flag );
    	
    	if (m_shr_sem < 0)
    	{
    		flag |= IPC_CREAT;
    		
    		m_shr_sem  = (int) semget( m_semKey, 2, flag );
    		
    		if (m_shr_sem < 0)
    		{
    			return -1;
    		}
    	}
    	
    	union semun      arg;
    	if (flag & IPC_CREAT)
    	{
    		// could use SETALL?
    		arg.val = 1;
    		semctl(m_shr_sem, 1, SETVAL, arg);
    		semctl(m_shr_sem, 0, SETVAL, arg);
    		fprintf(stdout, "CNamedSemaphore::CreateNamedSemaphore IPC_CREAT count=%d\n", arg.val);
    		// for debugging purposes, check value
    		arg.val = semctl(m_shr_sem, 1, GETVAL);
    		fprintf(stdout, "CNamedSemaphore::CreateNamedSemaphore IPC_CREAT count=%d\n", arg.val);
    	}
    	else
    	{
    		Lock();
    		arg.val = semctl(m_shr_sem, 1, GETVAL);
    		arg.val++;
    		if (semctl(m_shr_sem, 1, SETVAL, arg) == -1)
    		{
    			Unlock();
    			return -1;
    		}
    		Unlock();
    		// for debugging purposes, check value
    		fprintf(stdout, "CNamedSemaphore::CreateNamedSemaphore count=%d\n", arg.val);
    	}
    	// for debugging purposes, check value
    	arg.val = semctl(m_shr_sem, 1, GETVAL);
    	fprintf(stdout, "CNamedSemaphore::CreateNamedSemaphore GETVAL count=%d\n", arg.val);
    
    	return 0;
    }
    
    
    int	CNamedSemaphore::Lock()
    {
    	if (m_shr_sem < 0)
    	{
    		return -1;
    	}
    
    	struct sembuf   semBuf;
    	semBuf.sem_num = 0;
    	semBuf.sem_op = -1;
    	semBuf.sem_flg = SEM_UNDO;
    	if (semop(m_shr_sem, &semBuf, 1) != 0)
    		return -1;
    
    	return 0;
    }
    
    int	CNamedSemaphore::TryLock()
    {
    	if (m_shr_sem < 0)
    	{
    		return -1;
    	}
    
    	if (m_shr_sem < 0)
    	{
    		return -1;
    	}
    
    	struct sembuf   semBuf;
    	semBuf.sem_num = 0;
    	semBuf.sem_op = -1;
    	semBuf.sem_flg = SEM_UNDO | IPC_NOWAIT;
    	errno = 0;
    	if (semop(m_shr_sem, &semBuf, 1) == -1)
    	{
    		if (errno == EAGAIN)
    		{
    			return -1;
    		}
    		// ??? Check errno!!!
    		assert(false);
    	}
    	return 0;
    }
    
    int	CNamedSemaphore::Unlock()
    {
    	if (m_shr_sem < 0)
    	{
    		return -1;
    	}
    
    	struct sembuf   semBuf;
    	semBuf.sem_num = 0;
    	semBuf.sem_op  = 1;
    	semBuf.sem_flg = SEM_UNDO;
    	
    	if (semop(m_shr_sem, &semBuf, 1) != 0)
    		return -1;
    
    	return 0;
    }
    Thank you for the help!

  6. #5
    Just Joined!
    Join Date
    Jan 2007
    Posts
    5
    It is not clear from my post but the second semaphore is used as a "counting semaphore". Every time I create the semaphore set, I increase the count of the second semaphore. Everytime I destroy the set, I decrease the count. When it reaches 0, I call semctl(IPC_RMID).

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •