Thread: Mutex and Shared Memory Segment Questions.

  1. #1
    Registered User
    Join Date
    Feb 2009
    Posts
    6

    Mutex and Shared Memory Segment Questions.

    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

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    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?
    How do you do it in the first place? How do you prevent one process from finding the shared memory and using it before the processes that allocated the shared memory has initialized the mutex there?

    I have little experience with interprocess synchronization on Linux, but I think file locks would be better here.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    Registered User
    Join Date
    Feb 2009
    Posts
    6
    How do you do it in the first place? How do you prevent one process from finding the shared memory and using it before the processes that allocated the shared memory has initialized the mutex there?
    I may be wrong but given that shmget returns an unique ID based on a key, I assume that if multiple processes attempt to create a memory segment with the same key at the same time, only one of them can succeed. The other ones will fail and try to find the already created segment. I should thus always end up with one proper segment.

    The man pages say that the result of pthread_mutex_init on a already initialized mutex is undefined and may fail with EBUSY depending on the implementation. I guess I've been going on the assumption that it will fail... lol
    I will have to make sure that pthread_mutex_init is never called on an already initialized mutex...

    To answer my own question, I found out that to keep from ending with a locked mutex after a bad process termination, pthread_mutexattr_setrobust_no can do the job.

    My big problem right now is still the deletion of the memory segments...

    PS: I'm not really working with files, I'm actually working with USB devices. The code shown is just used to assess the feasibility of the global mutex... That's why I didn't really look into file locks. Thanks for the suggestion though

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    I should thus always end up with one proper segment.
    Yes, one memory segment. But imagine the following sequence of two threads:

    Code:
    A -> Create SHM
    B -> Attempt and fail to create SHM
    B -> Lookup SHM (assume mutex is initialized)
    B -> Try to lock mutex
    A -> Initialize mutex
    What then?

    Regarding file locks: I don't mean to lock the device file (although that's an interesting idea, too). Just a file that you create for the specific purpose of locking.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    Registered User
    Join Date
    Feb 2009
    Posts
    6
    Up until now, processes always performed pthread_mutex_init (whether or not they were the ones who created the shared segment)... I was under the impression that only the first call to pthread_mutex_init would pass and all others would fail but I traced the code and that isn't the case. The result is undefined in general and it actually re-initializes the mutex on my machine even if the mutex is locked!

    I reworked my test program to include space for a pthread_once_t struct in my shared segment. shmget clears all memory to zero when it creates a segment which is what is wanted for the initial value of pthread_once_t. Processes now get the memory segment though shmget (by creating if it doesn;'t exist yet or retreiving it if creation fails). They then call pthread_once on the shared pthread_once_t struct ensuring that my initialization method only gets called once for as long as the shared segment is alive.

    Here is the code
    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 pthread_mutex_t * GlobalMutex;
    static char * myLine = PROG1;
    static int shmid;
    
    
    void * getSharedMemPtr(void)
    {
      key_t key = 0x11d7;
      FILE * fp;
    
      
      shmid = shmget(key, sizeof(pthread_mutex_t) + sizeof(pthread_once_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) + sizeof(pthread_once_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  NULL;
    	    }
    	  else
    	    {
    	      //printf("Shared memory attached and marked for deletion.\n");
    	      //shmctl(shmid, IPC_RMID, NULL);
    	      printf("Shared memory attached\n");
    	      return 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  NULL;
    	}
          else
    	{
    	  //printf("Shared memory attached and marked for deletion.\n");
    	  //shmctl(shmid, IPC_RMID, NULL);
    	  printf("Shared memory attached\n");
    	  return  poSharedMem;
    	}
        }
    
      return  NULL;
    }
    
    int detatchFromSharedMem(void * poSharedMem)
    {
      printf("Marking shared memory for destruction and detaching from it.\n");
      shmctl(shmid, IPC_RMID, NULL);
      return shmdt(poSharedMem);
    }
    
    void sharedMemoryMutexInit(void)
    {
      
      if (NULL != GlobalMutex)
        {
          pthread_mutexattr_t oMutexAttribute;
    
          pthread_mutexattr_init(&oMutexAttribute);
    
          if (0 == pthread_mutexattr_setrobust_np(&oMutexAttribute, PTHREAD_MUTEX_ROBUST_NP))
    	{
    	  if (0 == pthread_mutexattr_setpshared(&oMutexAttribute, PTHREAD_PROCESS_SHARED))
    	    {
    	      if (0 == pthread_mutexattr_settype(&oMutexAttribute, PTHREAD_MUTEX_RECURSIVE))
    		{
    		  if (0 == pthread_mutex_init(GlobalMutex, &oMutexAttribute))
    		    {
    		      printf("Mutex initialized \n");
    		      pthread_mutexattr_destroy(&oMutexAttribute);
    		      return;
    		    }
    		  else
    		    {
    		      printf("pthread_mutex_init Failure\n");		  
    		    }
    		}
    	      else
    		{
    		  printf("pthread_mutexattr_settype Failure\n");
    		}
    	    }
    	  else
    	    {
    	      printf("pthread_mutexattr_setpshared Failure\n");
    	    }
    	}
          else
    	{
    	      printf("pthread_mutexattr_setrobust_np Failure\n");
    	}
    
          pthread_mutexattr_destroy(&oMutexAttribute);
        }
      
      return;
    }
    
    int main(void)
    {
    
      FILE * fp;
     
      void * poSharedMem = getSharedMemPtr();
      GlobalMutex = (pthread_mutex_t *)poSharedMem;
    
      pthread_once_t * pOnce = (pthread_once_t *)( ((char *)poSharedMem) + sizeof(pthread_mutex_t) );
    
      pthread_once(pOnce, sharedMemoryMutexInit);
      
      if (GlobalMutex == NULL)
        {
          return 0;
        }
    
      int mutexLockResult;
      
      for (int i =0; i < 100000; i ++)
        {
          mutexLockResult = pthread_mutex_lock(GlobalMutex);
          if (0 == mutexLockResult)
    	{
    	  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);
    	}
          else if (EOWNERDEAD == mutexLockResult)
    	{
    	  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_consistent_np(GlobalMutex);
    	  pthread_mutex_unlock(GlobalMutex);
    	}
        }
      
      
      if(NULL != GlobalMutex)
        {
          detatchFromSharedMem(GlobalMutex);
        }
    }
    
    //EOF

  6. #6
    Registered User
    Join Date
    Feb 2009
    Posts
    6
    So, does anyone know of a method which would allow me to get the shmid of a shared memory segment that was previously marked for deletion? I need to be able to get a memory segment that previously marked for deletion, attach to it and read/write to it...

    Any help would be appreciated

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by MadDog View Post
    So, does anyone know of a method which would allow me to get the shmid of a shared memory segment that was previously marked for deletion? I need to be able to get a memory segment that previously marked for deletion, attach to it and read/write to it...

    Any help would be appreciated
    You can enumerate all shmids with shmids().

    There is no standard way to determine if the deletion flag was set. You may be able to poke through /proc to extract this info.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  8. #8
    Registered User
    Join Date
    Feb 2009
    Posts
    6
    Thanks brewbuck,
    Is there any way to know if a shmid was created through a particular key? I don't really care if the segment is marked for deletion or not. I just want to have a common shared segment for many independent processes. My problem is that attempting to get the shmid of a segment - that was previously created and marked for deletion - through shmget(my_key, ...) creates a new segment... What I want is that segment (the one I created in the first place), not just any segment marked for deletion...

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by MadDog View Post
    Thanks brewbuck,
    Is there any way to know if a shmid was created through a particular key? I don't really care if the segment is marked for deletion or not. I just want to have a common shared segment for many independent processes. My problem is that attempting to get the shmid of a segment - that was previously created and marked for deletion - through shmget(my_key, ...) creates a new segment... What I want is that segment (the one I created in the first place), not just any segment marked for deletion...
    You should be able to find the key with:

    Code:
    struct shmid_ds ds;
    
    shmctl(shmid, IPC_STAT, &ds);
    ds.shm_perm.key; /* Here's the key */
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  10. #10
    Registered User
    Join Date
    Feb 2009
    Posts
    6
    Thanks Brewbuck,
    I tried what you suggested but shmids() doesn't seem to exist in Linux man pages; the only reference I found of it is in the Sun Microsystem system calls man pages... I'm not a linux/unix guru so I'm guessing that it's a function call that is proper to system running Solaris or something... I however got around that by reading /proc/sysvipc/shm as you suggested but ran into another problem.
    The problem is that ds.shm_perm.key gets reseted to 0 whenever the shared segment associated to shmid is marked for deletion and I can't tell if it's mine or not anymore...

  11. #11
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by MadDog View Post
    Thanks Brewbuck,
    I tried what you suggested but shmids() doesn't seem to exist in Linux man pages; the only reference I found of it is in the Sun Microsystem system calls man pages... I'm not a linux/unix guru so I'm guessing that it's a function call that is proper to system running Solaris or something... I however got around that by reading /proc/sysvipc/shm as you suggested but ran into another problem.
    The problem is that ds.shm_perm.key gets reseted to 0 whenever the shared segment associated to shmid is marked for deletion and I can't tell if it's mine or not anymore...
    Bummer...

    I think in your situation it might be better to use named, memory-mapped files instead of SysV shared memory. The filename acts as both key and id at the same time, is easily detectable by looking in the file system, can be deleted before the last person unmaps the segment, i.e. it meets your requirements.

    It even provides the added benefit of never leaking -- once the last user unmaps the file, the pages are freed, unlike when the last user of a shm segment forgets to delete it!
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  12. #12
    Registered User oteros's Avatar
    Join Date
    Mar 2009
    Location
    Madrid, Spain
    Posts
    7
    Hi!
    I'm actually developing a C routines (linux) that uses mutexes (up to 256) in shared memory to control up to 255 shared memory segments. If interested today how solve situations about these complexities, please send me one email and I will send code us.
    The code is not yet completely terminated but the control and recovering it is..
    G. Oteros.

  13. #13
    Registered User
    Join Date
    Apr 2010
    Posts
    2
    Quote Originally Posted by MadDog View Post
    Thanks Brewbuck,
    I tried what you suggested but shmids() doesn't seem to exist in Linux man pages; the only reference I found of it is in the Sun Microsystem system calls man pages... I'm not a linux/unix guru so I'm guessing that it's a function call that is proper to system running Solaris or something... I however got around that by reading /proc/sysvipc/shm as you suggested but ran into another problem.
    The problem is that ds.shm_perm.key gets reseted to 0 whenever the shared segment associated to shmid is marked for deletion and I can't tell if it's mine or not anymore...
    ftok() may return key in "int shmget(key_t key, int size, int shmflg);".
    BTW, PTHREAD_PROCESS_SHARED and PTHREAD_MUTEX_RECURSIVE are mutually exclusive.
    Last edited by cjrcl; 04-28-2010 at 01:37 PM.

  14. #14
    Registered User jeffcobb's Avatar
    Join Date
    Dec 2009
    Location
    Henderson, NV
    Posts
    875
    At the risk of sounding like a smartass, the first thing I would be doing is fixing your reason for the processes ending unexpectedly. Seriously. I am not trying to dog out the OP but he seems to be in search for a patch to cover symptoms of a larger issue.

    However if the issue is managing separate processes and how they access a device, a file lock would not be a bad way to go. I know you are not that enthused with the idea of a file lock but remember on *NIX everything is a file so it could be a socket, anything. As an added bonus, you get read/write locks out of it in the bargain. This is not to say this is the answer for every situation but it would work in yours. If you are dead-set against it, the only other way I know of to do what you want is to set up a single instance of the process to be the first one started and the last one stopped, even if it spends most of its time asleep. Let *it* manage things via a SysV message queue and the other instances of your process do whatever it is you need them to do...
    C/C++ Environment: GNU CC/Emacs
    Make system: CMake
    Debuggers: Valgrind/GDB

  15. #15
    Registered User
    Join Date
    Apr 2010
    Posts
    2
    Quote Originally Posted by MadDog View Post
    Up until now, processes always performed pthread_mutex_init (whether or not they were the ones who created the shared segment)... I was under the impression that only the first call to pthread_mutex_init would pass and all others would fail but I traced the code and that isn't the case. The result is undefined in general and it actually re-initializes the mutex on my machine even if the mutex is locked!

    I reworked my test program to include space for a pthread_once_t struct in my shared segment. shmget clears all memory to zero when it creates a segment which is what is wanted for the initial value of pthread_once_t. Processes now get the memory segment though shmget (by creating if it doesn;'t exist yet or retreiving it if creation fails). They then call pthread_once on the shared pthread_once_t struct ensuring that my initialization method only gets called once for as long as the shared segment is alive.

    Here is the code
    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 pthread_mutex_t * GlobalMutex;
    static char * myLine = PROG1;
    static int shmid;
    
    
    void * getSharedMemPtr(void)
    {
      key_t key = 0x11d7;
      FILE * fp;
    
      
      shmid = shmget(key, sizeof(pthread_mutex_t) + sizeof(pthread_once_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) + sizeof(pthread_once_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  NULL;
    	    }
    	  else
    	    {
    	      //printf("Shared memory attached and marked for deletion.\n");
    	      //shmctl(shmid, IPC_RMID, NULL);
    	      printf("Shared memory attached\n");
    	      return 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  NULL;
    	}
          else
    	{
    	  //printf("Shared memory attached and marked for deletion.\n");
    	  //shmctl(shmid, IPC_RMID, NULL);
    	  printf("Shared memory attached\n");
    	  return  poSharedMem;
    	}
        }
    
      return  NULL;
    }
    
    int detatchFromSharedMem(void * poSharedMem)
    {
      printf("Marking shared memory for destruction and detaching from it.\n");
      shmctl(shmid, IPC_RMID, NULL);
      return shmdt(poSharedMem);
    }
    
    void sharedMemoryMutexInit(void)
    {
      
      if (NULL != GlobalMutex)
        {
          pthread_mutexattr_t oMutexAttribute;
    
          pthread_mutexattr_init(&oMutexAttribute);
    
          if (0 == pthread_mutexattr_setrobust_np(&oMutexAttribute, PTHREAD_MUTEX_ROBUST_NP))
    	{
    	  if (0 == pthread_mutexattr_setpshared(&oMutexAttribute, PTHREAD_PROCESS_SHARED))
    	    {
    	      if (0 == pthread_mutexattr_settype(&oMutexAttribute, PTHREAD_MUTEX_RECURSIVE))
    		{
    		  if (0 == pthread_mutex_init(GlobalMutex, &oMutexAttribute))
    		    {
    		      printf("Mutex initialized \n");
    		      pthread_mutexattr_destroy(&oMutexAttribute);
    		      return;
    		    }
    		  else
    		    {
    		      printf("pthread_mutex_init Failure\n");		  
    		    }
    		}
    	      else
    		{
    		  printf("pthread_mutexattr_settype Failure\n");
    		}
    	    }
    	  else
    	    {
    	      printf("pthread_mutexattr_setpshared Failure\n");
    	    }
    	}
          else
    	{
    	      printf("pthread_mutexattr_setrobust_np Failure\n");
    	}
    
          pthread_mutexattr_destroy(&oMutexAttribute);
        }
      
      return;
    }
    
    int main(void)
    {
    
      FILE * fp;
     
      void * poSharedMem = getSharedMemPtr();
      GlobalMutex = (pthread_mutex_t *)poSharedMem;
    
      pthread_once_t * pOnce = (pthread_once_t *)( ((char *)poSharedMem) + sizeof(pthread_mutex_t) );
    
      pthread_once(pOnce, sharedMemoryMutexInit);
      
      if (GlobalMutex == NULL)
        {
          return 0;
        }
    
      int mutexLockResult;
      
      for (int i =0; i < 100000; i ++)
        {
          mutexLockResult = pthread_mutex_lock(GlobalMutex);
          if (0 == mutexLockResult)
    	{
    	  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);
    	}
          else if (EOWNERDEAD == mutexLockResult)
    	{
    	  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_consistent_np(GlobalMutex);
    	  pthread_mutex_unlock(GlobalMutex);
    	}
        }
      
      
      if(NULL != GlobalMutex)
        {
          detatchFromSharedMem(GlobalMutex);
        }
    }
    
    //EOF
    For shmget() prohibbits simutaneous initializations of a block of memory area, one does not have to rely on pthread_once() to get the GlobalMutex therein initialized instead of taking advantage of shmget() itself.

    Modified code:
    Code:
    void sharedMemoryMutexInit(void * poSharedMem)
    {
    	pthread_mutex_t * GlobalMutex = (pthread_mutex_t *) poSharedMem;
    	pthread_mutexattr_t oMutexAttribute;
    	pthread_mutexattr_init(&oMutexAttribute);
    	if(0 == pthread_mutexattr_setrobust_np(&oMutexAttribute, PTHREAD_MUTEX_ROBUST_NP))
    	{
    		if(0 == pthread_mutexattr_setpshared(&oMutexAttribute, PTHREAD_PROCESS_SHARED))
    		{
    			if(0 == pthread_mutexattr_settype(&oMutexAttribute, PTHREAD_MUTEX_ERRORCHECK))
    			{
    				if(0 == pthread_mutex_init(GlobalMutex, &oMutexAttribute))
    				{
    					printf("GlobalMutex initialized.\n");
    				}
    				else
    				{
    					printf("pthread_mutex_init Failure.\n");
    				}
    			}
    			else
    			{
    				printf("pthread_mutexattr_settype Failure.\n");
    			}
    		}
    		else
    		{
    			printf("pthread_mutexattr_setpshared Failure.\n");
    		}
    	}
    	else
    	{
    		printf("pthread_mutexattr_setrobust_np Failure.\n");
    	}
    	pthread_mutexattr_destroy(&oMutexAttribute);
    }
    
    void * getSharedMemPtr(key_t key, size_t size, bool mutex)
    {
    	int shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0x1b6);
    	if(-1 == shmid)
    	{
    		//printf("Could not create shared mem.\nWill attempt to find it.\n");
    		shmid = shmget(key, size, IPC_CREAT | 0x1b6);
    		if(-1 == shmid)
    		{
    			printf("\tCould not find it either.\n");
    		}
    		else
    		{
    			//printf("\tFound shared memory.\n");
    			void * poSharedMem = shmat(shmid, 0, 0);
    			if((void *) -1 == poSharedMem)
    			{
    				printf("Could not attatch shared memory to address space.\n");
    			}
    			else
    			{
    				//printf("Shared memory attached.\n");
    				return poSharedMem;
    			}
    		}
    	}
    	else
    	{
    		printf("Shared memory created.\n");
    		void * poSharedMem = shmat(shmid, 0, 0);
    		if((void *) -1 == poSharedMem)
    		{
    			printf("Could not attatch shared memory to address space.\n");
    		}
    		else
    		{
    			//printf("Shared memory attached.\n");
    			if(mutex)
    			{
    				sharedMemoryMutexInit(poSharedMem);
    			}
    			return poSharedMem;
    		}
    	}
    	return 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem with shared memory
    By kotoko in forum C Programming
    Replies: 2
    Last Post: 01-06-2009, 02:26 PM
  2. shared memory & mutex
    By lollobrigido in forum Linux Programming
    Replies: 3
    Last Post: 02-22-2008, 04:34 PM
  3. Threading and mutex's
    By megatron09 in forum C++ Programming
    Replies: 14
    Last Post: 09-07-2006, 02:40 PM
  4. thread and shared memory manipulation
    By taher84 in forum C Programming
    Replies: 4
    Last Post: 07-25-2006, 04:05 AM
  5. Thread Synchronization in Win32
    By passionate_guy in forum C Programming
    Replies: 0
    Last Post: 02-06-2006, 05:34 AM

Tags for this Thread