LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 02-06-2007, 10:55 AM   #1
gcote
LQ Newbie
 
Registered: Feb 2007
Location: Montreal, Canada
Distribution: Ubuntu 6.10
Posts: 2

Rep: Reputation: 0
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!

Last edited by gcote; 02-06-2007 at 01:15 PM.
 
Old 02-06-2007, 11:46 PM   #2
paulsm4
Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
Hi -

In Windows, named semaphores (and synchronization objects in general) are reference-counted: the object remains until the last person using it cleans up.

SysV IPCs, however, are very different. If *anybody* deletes the object (given, of course, the privilege to delete it) - boom! It's gone.

You need to keep your own reference count on the semaphore. Frankly, I find it useful to create a second, "counting semaphore" to keep the reference count on my "working semaphore". Your suggestion about a shared global is another solution (although you're probably going to need to create a new semaphore anyway, just to protect the global variable).

Just a thought .. PSM

Last edited by paulsm4; 02-06-2007 at 11:47 PM.
 
Old 02-07-2007, 12:13 PM   #3
gcote
LQ Newbie
 
Registered: Feb 2007
Location: Montreal, Canada
Distribution: Ubuntu 6.10
Posts: 2

Original Poster
Rep: Reputation: 0
Thank you!

This is a great idea!

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;
}
One thing about the shared memory that I didn't like is the fact that the minimum size is 4096 (getpagesize()). If at one point, I need to create many shared semaphores, one 4k block of shared memory per semaphore adds up quickly. I would have to implement my own shared memory manager.

Thank you very much for the help!

G.

Last edited by gcote; 02-07-2007 at 12:25 PM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Hi semaphore and shared memory rammu_sivraj Linux - Newbie 4 06-29-2006 11:49 AM
shared memory/semaphore problem V_Ganesh Programming 1 03-31-2005 10:58 PM
How to change shared memory and semaphore config on RHL9? ryanw Linux - Software 1 01-18-2005 10:14 AM
weapons of mass destruction Mohsen Linux - General 2 07-06-2003 12:46 PM
RPM's and the destruction of Linux bickford General 6 10-29-2000 02:36 PM


All times are GMT -5. The time now is 08:58 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration