Hi all,

I'm writing a program that reads and writes from a device. The thing is that many independent instances of the program may be run at once and synchronization is required to make sure that only one process at a time can communicate with the device in question.
To do so, I created a segment of memory (shmget) and initialized it as a mutex (pthread_mutex_init). This resulted in having a piece of memory that any process can use as a mutex using the regular pthread_mutex_lock/unlock functions.

This methods seems to work fine but I have a few issues with it:

1) If a process/thread locks the mutex and is terminated abnormally before it can release it, the mutex is then locked "forever" and all processes/threads waiting on it "freeze". I know I can set a timeout when attempting to claim a mutex using pthread_mutex_timedlock to keep from "freezing" but is there a way for a process/thread to unlock a mutex without being the one that locked it in the first place? I can probably clear the shared memory segment manually and call pthread_mutex_init on it again but how can I make sure two processes don't attempt to do so at the same time?

2) Shared segments need to be marked for deletion if we want the OS to release them once all processes that were attached to them stop (or detach from them). The problem is that I want to be able to start a new instance of my program at anytime. Because of that, I can't mark the memory segment for destruction right after creating it; if I do so, new program instances loose the ability to attach to the segments. Is there a way to mark a shared memory segment for destruction and still be able to attach to it while it's alive?

Thanks for the help.

Here is test code for the global mutexes if anyone is interested.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <pthread.h>

#define PROG1 "This is program 1\n"
#define PROG2 "This is program 2\n"

static char * myLine = PROG1;
static int shmid;

pthread_mutex_t * getSharedMutexPtr(void)
{
  key_t key = 0x11d7;
  FILE * fp;

  
  shmid = shmget(key, sizeof(pthread_mutex_t), IPC_CREAT | IPC_EXCL | 0x1b6);
  
  if (0 > shmid)
    {
      printf("Could not create shared mem.\n");
      printf("Will attempt to find it.\n");
      
      shmid = shmget(key, sizeof(pthread_mutex_t), 0x1b6);
      
      if(0 > shmid)
	{
	  printf("\tCouldnt find it either\n");
	}
      else
	{
	  
	  fp = fopen("MutextestFile.txt", "r+");
          fclose(fp);	
	  
	  myLine = PROG2;
	  printf("\tFound shared memory");
	  void * const poSharedMem = shmat(shmid, NULL, 0);
	  
	  if(((void *)-1) == poSharedMem)
	    {
	      printf("Could not attatch shared memory to address space.\n");
	      return (pthread_mutex_t *) NULL;
	    }
	  else
	    {
	      //THIS IS WHERE I WOULD LIKE TO MARK MEMORY FOR DESTRUCTION
	      //printf("Shared memory attached and marked for deletion.\n");
	      //shmctl(shmid, IPC_RMID, NULL);
	      printf("Shared memory attached\n");
	      return (pthread_mutex_t *) poSharedMem;	     
	    }
	}
    } 
  else
    {
      fp = fopen("MutextestFile.txt", "w+");
      fclose(fp);

      myLine = PROG1;
      printf("Shared memory created.\n");
      
      void * const poSharedMem = shmat(shmid, NULL, 0);
      
      if(((void *)-1) == poSharedMem)
	{
	  printf("Could not attatch shared memory to address space.\n");
	  return (pthread_mutex_t *) NULL;
	}
      else
	{
          //THIS IS WHERE I WOULD LIKE TO MARK MEMORY FOR DESTRUCTION
	  //printf("Shared memory attached and marked for deletion.\n");
	  //shmctl(shmid, IPC_RMID, NULL);
	  printf("Shared memory attached\n");
	  return (pthread_mutex_t *) poSharedMem;
	}
    }

  return (pthread_mutex_t *) NULL;
}

int detatchFromSharedMem(void * poSharedMem)
{
  //THIS IS WHERE I MARK MEMORY FOR DESTRUCTION CURRENTLY BUT NOT HAPPY WIHT IT
  printf("Marking shared memory for destruction and detaching from it.\n");
  shmctl(shmid, IPC_RMID, NULL);
  return shmdt(poSharedMem);
}

pthread_mutex_t * sharedMemoryMutexInit(void)
{
  pthread_mutex_t * pMutex = getSharedMutexPtr();

  if (NULL != pMutex)
    {
      pthread_mutexattr_t oMutexAttribute;

      pthread_mutexattr_init(&oMutexAttribute);

      if (0 == pthread_mutexattr_setpshared(&oMutexAttribute, PTHREAD_PROCESS_SHARED))
        {
	  if (0 == pthread_mutexattr_settype(&oMutexAttribute, PTHREAD_MUTEX_RECURSIVE))
            {
	      if (0 == pthread_mutex_init(pMutex, &oMutexAttribute))
                {
		  printf("Mutex initialized \n");
		  return pMutex;
                }
	      else
                {
		  printf("pthread_mutex_init Failure\n");		  
                }
            }
	  else
            {
	      printf("pthread_mutexattr_settype Failure\n");
            }
        }
      else
        {
	  printf("pthread_mutexattr_setpshared Failure\n");
        }

      pthread_mutexattr_destroy(&oMutexAttribute);
    }
  
  return (pthread_mutex_t *) NULL;
}

int main(void)
{
  pthread_mutex_t * GlobalMutex;
  FILE * fp;

  GlobalMutex = sharedMemoryMutexInit();
  
  if (GlobalMutex == NULL)
    {
      return 0;
    }
  
  for (int i =0; i < 100000; i ++)
    {
      if (0 == pthread_mutex_lock(GlobalMutex))
	{
	  fp = fopen("MutextestFile.txt", "r+");
	  if (NULL != fp)
	    {
	      fseek(fp, 0, SEEK_END);
	      fprintf(fp, "%4d - ", i+1);
	      fprintf(fp, myLine);
	      fclose(fp);
	      fp = NULL;
	    }
	  pthread_mutex_unlock(GlobalMutex);
	}
    }
  
  
  if(NULL != GlobalMutex)
    {
      detatchFromSharedMem(GlobalMutex);
    }
}

//EOF