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