Problem with perror() calls affecting semaphore locking/unlocking - c++

I'm trying to do some basic parallel processing to do an odd-even sort on integers using POSIX shared memory segments and unnamed semaphores. I have pretty much everything working at this point, except for one final thing: if I do not perror() directly after semaphore locks/unlocks the code acts differently (and subsequently sorts incorrectly). If I leave the perror() calls directly after semaphore locks and unlocks in, the code sorts the array of integers perfectly.
int semaphoreCheck = sem_init(&(sharedData->swapSem), 1, 1);
if (semaphoreCheck == -1)
{
perror( "failed to initialize semaphore" );
exit(EXIT_FAILURE);
}
pid_t fork1;
fork1 = fork();
if (fork1 == 0)
{
// original.child
pid_t fork2;
fork2 = fork();
if (fork2 == 0)
{
// child.child
// do a portion of the sort here
while(sharedData->evenSwap || sharedData->oddSwap)
{
// obtain lock on the shared vector
// int commandCheck = shmctl(sharedID, SHM_LOCK, NULL);
int commandCheck = sem_wait(&(sharedData->swapSem));
perror("semaphore lock");
// if lock was obtained
if (commandCheck == 0)
{
sharedData->evenSwap = false;
for( int index = 1; index < arraySize - 1; index +=2)
{
if( sharedData->vecData[index] > sharedData->vecData[index + 1] )
{
int temp;
temp = sharedData->vecData[index];
sharedData->vecData[index] = sharedData->vecData[index+1];
sharedData->vecData[index+1] = temp;
sharedData->evenSwap = true;
}
}
// release lock on the shared vector
commandCheck = sem_post(&(sharedData->swapSem));
perror("semaphore unlock");
if (commandCheck == -1)
{
perror("failed to unlock shared semaphore");
}
}
else perror("failed to lock shared semaphore");
}
_exit(0);
}
else if (fork2 > 0)
{
// child.parent
// do a portion of the sort here
while(sharedData->evenSwap || sharedData->oddSwap)
{
// obtain lock on the shared vector
int commandCheck = sem_wait(&(sharedData->swapSem));
perror("semaphore lock");
// if lock was obtained
if (commandCheck == 0)
{
sharedData->oddSwap = false;
for( int index = 0; index < arraySize - 1; index +=2)
{
if( sharedData->vecData[index] > sharedData->vecData[index + 1] )
{
int temp;
temp = sharedData->vecData[index];
sharedData->vecData[index] = sharedData->vecData[index+1];
sharedData->vecData[index+1] = temp;
sharedData->oddSwap = true;
}
}
// release lock on the shared vector
commandCheck = sem_post(&(sharedData->swapSem));
perror("semaphore unlock");
if (commandCheck == -1)
{
perror("failed to unlock shared semaphore");
}
}
else perror("failed to lock shared semaphore");
}
_exit(0);
}
else
{
// child.error
// forking error.
perror("failed to fork in child");
exit(EXIT_FAILURE);
}
}
else if( fork1 > 0)
{
// original.parent
// wait for the child process to finish.
waitpid(fork1, NULL, 0);
}
else
{
// forking error
perror("failed to fork");
exit(EXIT_FAILURE);
}
I can only guess that this has to do with how the semaphore blocks the process if a wait cannot be fulfilled, but I do not understand how perror() calls fix it.

I think your problem may be related to the way you are (not) checking that the conditions still apply after you get the semaphore, or that the checking conditions are themselves wrong.
You have:
while(sharedData->evenSwap || sharedData->oddSwap)
{
// obtain lock on the shared vector
int commandCheck = sem_wait(&(sharedData->swapSem));
perror("semaphore lock");
// if lock was obtained
if (commandCheck == 0)
{
sharedData->oddSwap = false;
After you get the semaphore, you should probably validate that either sharedData->evenSwap or sharedData->oddSwap is still true, relinquishing the semaphore if not. This is a standard idiom; you check, lock and recheck, because the status may have changed between the original check and the time you gain the lock.
Under this hypothesis, the perror() calls alter the timing of the processes, allowing the conditions to stay unchanged for longer than when the perror() calls are not present. So, there is a timing problem here, somewhere.

Related

How to make it run sync?

Hello I want to sync two threads one incrementing a variable and other decrementing it.
The result that I want looks like:
Thread #0 j = 1
Thread #1 j = 0
Thread #0 j = 1
Thread #1 j = 0
And so on.. but my code sometimes works like that in some cases it print really weird values. I supose that I have some undefined behavior in somewhere but I can't figured out what is really happen.
My code consist in a HANDLE ghMutex that containg the handler of my mutex:
My main function:
int main(void)
{
HANDLE aThread[THREADCOUNT];
ghMutex = CreateMutex(NULL, FALSE, NULL);
aThread[0] = (HANDLE)_beginthreadex(NULL, 0, &inc, NULL, CREATE_SUSPENDED, 0);
aThread[1] = (HANDLE)_beginthreadex(NULL, 0, &dec, NULL, CREATE_SUSPENDED, 0);
ResumeThread(aThread[0]);
ResumeThread(aThread[1]);
WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
printf("j = %d\n", j);
for (int i = 0; i < THREADCOUNT; i++)
CloseHandle(aThread[i]);
CloseHandle(ghMutex);
return 0;
}
Inc function:
unsigned int __stdcall inc(LPVOID)
{
for (volatile int i = 0; i < MAX; ++i)
{
WaitForSingleObject(
ghMutex, // handle to mutex
INFINITE); // no time-out interval
j++;
printf("Thread %d j = %d\n", GetCurrentThreadId(), j);
ReleaseMutex(ghMutex);
}
_endthread();
return TRUE;
}
Dec function:
unsigned int __stdcall dec(void*)
{
for (volatile int i = 0; i < MAX; ++i)
{
WaitForSingleObject(
ghMutex, // handle to mutex
INFINITE); // no time-out interval
j--;
printf("Thread %d j = %d\n", GetCurrentThreadId(), j);
ReleaseMutex(ghMutex);
}
_endthread();
return TRUE;
}
I need a win api solution in std c++98.
A mutex is not the right tool to synchronize two threads, it is there to protect a resource. You do have a resource j which is protected by your mutex, however the sequence of which thread gets the lock is undefined, so you can have the case where dec gets called several times before inc has the chance to run.
If you want to synchronize the order of the threads you will have to use another synchronization primitive, for example a semaphore. You could, for example, increment the semaphore in inc and decrement it in dec. This would be the classic producer - consumer relationship where the producer will be stalled when the semaphore reaches its maximum value and the consumer will wait for items to consume.
Sorry, no WinAPI C++98 solution from me because that would be silly, but I hope I pointed you to the right direction.
windows mutex object guarantees exclusive ownership, but does not care about the ownership order. so that the same thread can capture several times in a row while others will wait.
for your task you need signal to another thread, when your task is done, and then wait for signal from another thread. for this task can be used event pair for example. thread (i) signal event (1-i) and wait on event (i). for optimize instead 2 calls -
SetEvent(e[1-i]); WaitForSingleObject(e[i], INFINITE);
we can use single call SignalObjectAndWait
SignalObjectAndWait(e[1-i], e[i], INFINITE, FALSE)
of course start and end of loop require special care. for inc
HANDLE hObjectToSignal = _hEvent[1], hObjectToWaitOn = _hEvent[0];
for (;;)
{
_shared_value++;
if (!--n)
{
SetEvent(hObjectToSignal);
break;
}
SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, INFINITE, FALSE);
}
and for dec
HANDLE hObjectToSignal = _hEvent[0], hObjectToWaitOn = _hEvent[1];
WaitForSingleObject(hObjectToWaitOn, INFINITE);
for (;;)
{
--_shared_value;
if (!--n)
{
break;
}
SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, INFINITE, FALSE);
}
if write full test, with error checking
struct Task
{
HANDLE _hEvent[4];
ULONG _n;
LONG _iTasks;
LONG _shared_value;
Task()
{
RtlZeroMemory(this, sizeof(*this));
}
~Task()
{
ULONG n = RTL_NUMBER_OF(_hEvent);
do
{
if (HANDLE hEvent = _hEvent[--n]) CloseHandle(hEvent);
} while (n);
}
ULONG WaitTaskEnd()
{
return WaitForSingleObject(_hEvent[2], INFINITE);
}
ULONG WaitTaskReady()
{
return WaitForSingleObject(_hEvent[3], INFINITE);
}
void SetTaskReady()
{
SetEvent(_hEvent[3]);
}
void End()
{
if (!InterlockedDecrement(&_iTasks)) SetEvent(_hEvent[2]);
}
void Begin()
{
InterlockedIncrementNoFence(&_iTasks);
}
static ULONG WINAPI IncThread(PVOID p)
{
return reinterpret_cast<Task*>(p)->Inc(), 0;
}
void Inc()
{
if (WaitTaskReady() == WAIT_OBJECT_0)
{
if (ULONG n = _n)
{
HANDLE hObjectToSignal = _hEvent[1], hObjectToWaitOn = _hEvent[0];
for (;;)
{
if (_shared_value) __debugbreak();
if (n < 17) DbgPrint("Inc(%u)\n", n);
_shared_value++;
if (!--n)
{
SetEvent(hObjectToSignal);
break;
}
if (SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, INFINITE, FALSE) != WAIT_OBJECT_0)
{
break;
}
}
}
}
End();
}
static ULONG WINAPI DecThread(PVOID p)
{
return reinterpret_cast<Task*>(p)->Dec(), 0;
}
void Dec()
{
if (WaitTaskReady() == WAIT_OBJECT_0)
{
if (ULONG n = _n)
{
HANDLE hObjectToSignal = _hEvent[0], hObjectToWaitOn = _hEvent[1];
if (WaitForSingleObject(hObjectToWaitOn, INFINITE) == WAIT_OBJECT_0)
{
for (;;)
{
--_shared_value;
if (_shared_value) __debugbreak();
if (n < 17) DbgPrint("Dec(%u)\n", n);
if (!--n)
{
break;
}
if (SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, INFINITE, FALSE) != WAIT_OBJECT_0)
{
break;
}
}
}
}
}
End();
}
ULONG Create()
{
ULONG n = RTL_NUMBER_OF(_hEvent);
do
{
if (HANDLE hEvent = CreateEventW(0, n > 2, 0, 0)) _hEvent[--n] = hEvent;
else return GetLastError();
} while (n);
return NOERROR;
}
ULONG Start()
{
static PTHREAD_START_ROUTINE aa[] = { IncThread, DecThread };
ULONG n = RTL_NUMBER_OF(aa);
do
{
Begin();
if (HANDLE hThread = CreateThread(0, 0, aa[--n], this, 0, 0))
{
CloseHandle(hThread);
}
else
{
n = GetLastError();
End();
return n;
}
} while (n);
return NOERROR;
}
ULONG Start(ULONG n)
{
_iTasks = 1;
ULONG dwError = Start();
_n = dwError ? 0 : n;
SetTaskReady();
End();
return dwError;
}
};
void TaskTest(ULONG n)
{
Task task;
if (task.Create() == NOERROR)
{
task.Start(n);
task.WaitTaskEnd();
}
}
note, that no any sense declare local variable (which will be accessed only from single thread and not accessed by any interrupts, etc) as volatile
also when we write code, like:
// thread #1
write_shared_data();
SetEvent(hEvent);
// thread #2
WaitForSingleObject(hEvent, INFINITE);
read_shared_data();
inside SetEvent(hEvent); was atomic write to event state with release semantic (really stronger of course) and inside wait for event function - atomic read it state with more than acquire semantic. as result all what thread #1 write to memory before SetEvent - will be visible to thread #2 after Wait for event (if wait finished as result of call Set from thread #1)

Idea Behind Recursive Mutex Lock

I'm working on a school lab and we are instructed to create a recursive mutex lock for a counting program. I've written some code (which doesn't work), but I think that this is mostly because I do not understand the real idea behind using a recursive mutex lock. Could anyone elaborate what a recursive mutex lock should do/look like?
General Note: I'm not asking for an answer, just some clarification as to what recursive mutex lock should do.
Also, if anyone is curious, here is the code required for this. The code that I am editing/implementing is the recmutex.c.
recmutex.h
#include <pthread.h>
/*
* The recursive_mutex structure.
*/
struct recursive_mutex {
pthread_cond_t cond;
pthread_mutex_t mutex; //a non-recursive pthread mutex
pthread_t owner;
unsigned int count;
unsigned int wait_count;
};
typedef struct recursive_mutex recursive_mutex_t;
/* Initialize the recursive mutex object.
*Return a non-zero integer if errors occur.
*/
int recursive_mutex_init (recursive_mutex_t *mu);
/* Destroy the recursive mutex object.
*Return a non-zero integer if errors occur.
*/
int recursive_mutex_destroy (recursive_mutex_t *mu);
/* The recursive mutex object referenced by mu shall be
locked by calling pthread_mutex_lock(). When a thread
successfully acquires a mutex for the first time,
the lock count shall be set to one and successfully return.
Every time a thread relocks this mutex, the lock count
shall be incremented by one and return success immediately.
And any other calling thread can only wait on the conditional
variable until being waked up. Return a non-zero integer if errors occur.
*/
int recursive_mutex_lock (recursive_mutex_t *mu);
/* The recursive_mutex_unlock() function shall release the
recursive mutex object referenced by mu. Each time the owner
thread unlocks the mutex, the lock count shall be decremented by one.
When the lock count reaches zero, the mutex shall become available
for other threads to acquire. If a thread attempts to unlock a
mutex that it has not locked or a mutex which is unlocked,
an error shall be returned. Return a non-zero integer if errors occur.
*/
int recursive_mutex_unlock (recursive_mutex_t *mu);
recmutex.c: contains the functions for the recursive mutex
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include "recmutex.h"
int recursive_mutex_init (recursive_mutex_t *mu){
int err;
err = pthread_mutex_init(&mu->mutex, NULL);
if(err != 0){
perror("pthread_mutex_init");
return -1;
}else{
return 0;
}
return 0;
}
int recursive_mutex_destroy (recursive_mutex_t *mu){
int err;
err = pthread_mutex_destroy(&mu->mutex);
if(err != 0){
perror("pthread_mutex_destroy");
return -1;
}else{
return 1;
}
return 0;
}
int recursive_mutex_lock (recursive_mutex_t *mu){
if(mutex_lock_count == 0){
pthread_mutex_lock(&mu->mutex);
mu->count++;
mu->owner = pthread_self();
printf("%s", mu->owner);
return 0;
}else if(mutex_lock_count > 0){
pthread_mutex_lock(&mu->mutex);
mu->count++;
mu->owner = pthread_self();
return 0;
}else{
perror("Counter decremented incorrectly");
return -1;
}
}
int recursive_mutex_unlock (recursive_mutex_t *mu){
if(mutex_lock_count <= 0){
printf("Nothing to unlock");
return -1;
}else{
mutex_lock_count--;
pthread_mutex_unlock(&mu->mutex);
return 0;
}
}
count_recursive.cc: The counting program mentioned above. Uses the recmutex functions.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include "recmutex.h"
//argument structure for the thread
typedef struct _arg_{
int n1;
int n2;
int ntimes;
}Arg;
int count; //global counter
recursive_mutex_t mutex; //the recursive mutex
void do_inc(int n){
int ret;
if(n == 0){
return;
}else{
int c;
ret = recursive_mutex_lock(&mutex);
assert(ret == 0);
c = count;
c = c + 1;
count = c;
do_inc(n - 1);
ret = recursive_mutex_unlock(&mutex);
assert(ret == 0);
}
}
/* Counter increment function. It will increase the counter by n1 * n2 * ntimes. */
void inc(void *arg){
Arg * a = (Arg *)arg;
for(int i = 0; i < a->n1; i++){
for(int j = 0; j < a->n2; j++){
do_inc(a->ntimes);
}
}
}
int isPositiveInteger (const char * s)
{
if (s == NULL || *s == '\0' || isspace(*s))
return 0;
char * p;
int ret = strtol (s, &p, 10);
if(*p == '\0' && ret > 0)
return 1;
else
return 0;
}
int test1(char **argv){
printf("==========================Test 1===========================\n");
int ret;
//Get the arguments from the command line.
int num_threads = atoi(argv[1]); //The number of threads to be created.
int n1 = atoi(argv[2]); //The outer loop count of the inc function.
int n2 = atoi(argv[3]); //The inner loop count of the inc function.
int ntimes = atoi(argv[4]); //The number of increments to be performed in the do_inc function.
pthread_t *th_pool = new pthread_t[num_threads];
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
ret = recursive_mutex_init(&mutex);
assert(ret == 0);
printf("Start Test. Final count should be %d\n", num_threads * n1 * n2 * ntimes );
// Create threads
for(int i = 0; i < num_threads; i++){
Arg *arg = (Arg *)malloc(sizeof(Arg));
arg->n1 = n1;
arg->n2 = n2;
arg->ntimes = ntimes;
ret = pthread_create(&(th_pool[i]), &attr, (void * (*)(void *)) inc, (void *)arg);
assert(ret == 0);
}
// Wait until threads are done
for(int i = 0; i < num_threads; i++){
ret = pthread_join(th_pool[i], NULL);
assert(ret == 0);
}
if ( count != num_threads * n1 * n2 * ntimes) {
printf("\n****** Error. Final count is %d\n", count );
printf("****** It should be %d\n", num_threads * n1 * n2 * ntimes );
}
else {
printf("\n>>>>>> O.K. Final count is %d\n", count );
}
ret = recursive_mutex_destroy(&mutex);
assert(ret == 0);
delete [] th_pool;
return 0;
}
int foo(){
int ret;
printf("Function foo\n");
ret = recursive_mutex_unlock(&mutex);
assert(ret != 0);
return ret;
}
//test a thread call unlock without actually holding it.
int test2(){
int ret;
printf("\n==========================Test 2==========================\n");
pthread_t th;
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
ret = recursive_mutex_init(&mutex);
ret = pthread_create(&th, &attr, (void * (*)(void *))foo, NULL);
printf("Waiting for thread to finish\n");
ret = pthread_join(th, NULL);
assert(ret == 0);
return 0;
}
int main( int argc, char ** argv )
{
int ret;
count = 0;
if( argc != 5 ) {
printf("You must enter 4 arguments. \nUsage: ./count_recursive num_threads n1 n2 ntimes\n");
return -1;
}
if(isPositiveInteger(argv[1]) != 1 || isPositiveInteger(argv[2]) != 1 || isPositiveInteger(argv[3]) != 1 || isPositiveInteger(argv[4]) != 1 ){
printf("All the 4 arguments must be positive integers\n");
return -1;
}
test1(argv);
test2();
return 0;
}
The idea of a recursive mutex is that it can be successfully relocked by the thread that is currently holding the lock. For example:
if I had some mutexes like this (this is pseudocode):
mutex l;
recursive_mutex r;
In a single thread if I did this:
l.lock();
l.lock(); // this would hang the thread.
but
r.lock();
r.lock();
r.lock(); // this would all pass though with no issue.
In implimenting a recursive mutex you need to check what threadId has locked it, if it was locked, and if it matches the current thread id, return success.
The point of a recursive mutex, is to let you write this:
recursive_mutext_t rmutex;
void foo(...) {
recursive_lock_lock(&rmutex);
...
recursive_lock_unlock(&rmutex);
}
void bar(...) {
recursive_lock_lock(&rmutex);
...
foo(...);
...
recursive_lock_unlock(&rmutex);
}
void baz(...) {
...
foo(...);
...
}
The function foo() needs the mutex to be locked, but you want to be able to call it either from bar() where the same mutex is already locked, or from baz() where the mutex is not locked. If you used an ordinary mutex(), the thread would self-deadlock when foo() is called from bar() because the ordinary mutex lock() function will not return until the mutex is unlocked, and there's no other thread that will unlock it.
Your recursive_mutex_lock() needs to distinguish these cases; (1) The mutex is not locked, (2) the mutex is already locked, but the calling thread is the owner, and (3) the mutex is already locked by some other thread.
Case (3) needs to block the calling thread until the owner completely unlocks the mutex. At that point, it then converts to case (1). Here's a hint: Handle case (3) with a condition variable. That is to say, when the calling thread is not the owner, the calling thread should do a pthread_condition_wait(...) call.

Is this piece of code correct?

I compiled it on Linux with: g++ test.c -o test
I rewritten the original example.
Now made the first process to wait 2 seconds, (so that process2 could write on the shared memory), then I made process1 to read from that memory. Is this test correct?
Secondo question: where should I put:
shmdt(tests[0]); // or 1
shmctl(statesid, IPC_RMID, 0);
//Global scope
char *state[2];
//...
//...
struct teststruct {
int stateid;
teststruct *next;
//other things
};
void write(teststruct &t, char* what)
{
strcpy(state[t.next->stateid], what);
printf("\n\nI am (%d), I wrote on: %d", t.stateid, t.next->stateid);
}
void read(teststruct &t)
{
printf("\n\nI am (%d), I read: **%s**", t.stateid, state[t.stateid]);
}
int main() {
key_t key;
if ((key = ftok(".", 'a')) == -1) {
perror("ftok");
exit(1);
}
int statesid;
if ((statesid = shmget(key, sizeof(char*)*50, 0600 | IPC_CREAT )) == -1) {
perror("shmget error");
exit(1);
}
state[0] = (char*)shmat(statesid, NULL, 0);
state[1] = (char*)shmat(statesid, NULL, 0);
teststruct tests[2];
tests[0].stateid = 0;
tests[0].next = &tests[1];
tests[1].stateid = 1;
tests[1].next = &tests[0];
int t0, t1;
switch (t0 = fork()) {
case (0):
sleep(2);
read(tests[0]);
exit(0);
case (-1):
printf("\nError!");
exit(-1);
default:
wait();
}
switch (t1 = fork()) {
case (0):
write(tests[1], "1 write on 0 in theory.");
exit(0);
case (-1):
printf("\nError!");
exit(-1);
default:
wait();
}
return 0;
}
In particular I am asking if "state" is really shared between the two process, and If what I've done is a good way to do that.
My goal is to make char *state[2] shared (reading/modifying) between the two processes after fork.
You don't need to call shmat() twice. You've only allocated enough space for two pointers, so you can't communicate much between the two processes. And you can't rely on being able to copy a pointer to memory in the first process into shared memory and then have the second process read and use it. The address may be valid in the first process and not in the second; it may well point at completely different data in the second process (dynamic memory allocation in particular could screw this up). You can only rely on the contents of the shared memory being the same in both processes. You should allocate enough shared memory to hold the shared data.
However, with that said, the two processes should be sharing that small piece of shared memory, and in both processes, state[0] and state[1] will point at the shared memory and you should be able to communicate between the two by writing in the shared memory. Note that after forking, if either process changes the value stored in its state[0] or state[1], the other process will not see that change — the other process can only see what changes in the shared memory those pointers point to.
Of course, you've not set up any synchronization mechanism, so the access will likely be chaotic.
How can I modify my code just to make it works as intended (without considering synchronization issues)?
It isn't entirely clear how it is intended to work, which complicates answering the question. However, if you want (for sake of example) the child process to write a word to the shared memory and the parent process to read the word from shared memory, then you allocate enough shared memory for the biggest word you're willing to process, then arrange for the child to copy a word from its per-process memory into the shared memory (and notify the parent that it has done so), and then the parent can copy or read the word from shared memory and compare it with data from its per-process memory.
Because you have a parent-child process which are forks of the same process, you will find that the two processes share a lot of the same memory addresses containing the same information. This is, however, coincidental. You can have unrelated processes connect to shared memory, and they need not have any addresses in common. Thus, it would be trivial to get spurious results from your current setup.
Working Code
For some definitions of 'working', the following C++ code does. The code is subtly C++; the code assumes struct teststruct declares type teststruct, and uses references as parameters.
Note that the (revised) code in the question has its wait() calls infelicitously placed.
shm2.cpp
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
static char *state = 0;
struct teststruct
{
int stateid;
teststruct *next;
};
void sm_write(teststruct &t, char* /*what*/)
{
//strcpy(state[t.next->stateid], what);
printf("[%5d] I am (%d), I wrote on: %d\n", (int)getpid(), t.stateid, t.next->stateid);
}
void sm_read(teststruct &t)
{
printf("[%5d] I am (%d), I read: **%s**\n", (int)getpid(), t.stateid, state);
}
int main(void)
{
key_t key;
if ((key = ftok(".", 'a')) == -1) {
perror("ftok");
exit(1);
}
int statesid;
if ((statesid = shmget(key, sizeof(char)*512, 0600 | IPC_CREAT )) == -1) {
perror("shmget error");
exit(1);
}
if ((state = (char*)shmat(statesid, NULL, 0)) == 0)
{
perror("shmat");
exit(1);
}
sprintf(state, "This is a string in shared memory %d", 919);
teststruct tests[2];
tests[0].stateid = 0;
tests[0].next = &tests[1];
tests[1].stateid = 0;
tests[1].next = &tests[0];
int t0, t1;
if ((t0 = fork()) < 0)
{
perror("fork-1");
exit(1);
}
else if (t0 == 0)
{
sm_read(tests[0]);
printf("[%5d] sleeping\n", (int)getpid());
sleep(2);
printf("[%5d] waking\n", (int)getpid());
sm_read(tests[0]);
exit(0);
}
else if ((t1 = fork()) < 0)
{
perror("fork-2");
exit(-1);
}
else if (t1 == 0)
{
printf("[%5d] sleeping\n", (int)getpid());
sleep(1);
printf("[%5d] waking\n", (int)getpid());
strcpy(state, "1 write on 0 in theory.");
sm_write(tests[1], state);
exit(0);
}
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("PID %5d died with status 0x%.4X\n", corpse, status);
return 0;
}
Example run
[20440] sleeping
[20440] waking
[20440] I am (0), I wrote on: 0
[20439] I am (0), I read: **This is a string in shared memory 919**
[20439] sleeping
[20439] waking
[20439] I am (0), I read: **1 write on 0 in theory.**
PID 20440 died with status 0x0000
PID 20439 died with status 0x0000
You have a problem with the size of the shared memory. In:
(statesid = shmget(key, sizeof(char*)*2, 0600 | IPC_CREAT )
you are just reserving space for 2 pointers to char. You need to allocate enough space for all your data, that based on the struct is kind of linked structure. The code could be something like the following, though the purpose of the fork() and shared memory is not very clear to me:
struct teststruct {
int stateid;
teststruct *next;
//other things
};
void dosomething(teststruct &t){
//forget about global space, you don't need it
}
int main() {
key_t key;
if ((key = ftok(".", 'a')) == -1) {
perror("ftok");
exit(1);
}
int statesid;
int size_struct = sizeof(teststruct)*2; //assuming you will have only 1 level of linking
if ((statesid = shmget(key, size_struct, 0600 | IPC_CREAT )) == -1) {
perror("shmget error");
exit(1);
}
//if you need to hold just one teststruct object data, you can do
teststruct* p_test_struct = (teststruct*)shmat(statesid, NULL, 0);
for (int i=0; i<2; i++){
*p_test_struct = tests[i]; //this actually writes tests[i] into shared mem
int t0, t1;
switch (t0 = fork()) {
case (0):
dosomething(*p_test_struct);
exit(0);
case (-1):
printf("\nError!");
exit(-1);
default:
wait();
}
}
return 0;
}
No, it does not. Because you are using fork (multiprocess) instead of threads (multithread). Memory zones are not shared into parent and child process. You will have the same value into it on the child but after that it will be independent to the another one.

Memory Allocation for threads in C++

How to Explicitly Allocate memory to a Thread in C++ ? Am using Windows API for Multi-threading.While running sometimes it executes correctly but sometimes it shows "Heap Corruption","Unhandled Exception".Please guide me
This is the main() where i create the threads.
int main(int argc,char *argv[])
{
HANDLE hthread[MAX_THREADS];
//DWORD threadid;
FILETIME creation,exit,kernel,user;
SYSTEMTIME st1,st2;
//THREADENTRY32 entry;
char szEntrytime[255],szExittime[255];
directories.push_front(argv[1]);
files.clear();
Sem = CreateSemaphore(NULL,MAX_SEM_COUNT,MAX_SEM_COUNT,NULL);
if (Sem == NULL)
{
printf("CreateSemaphore error: %d\n", GetLastError());
return 1;
}
for(int i= 0;i<MAX_THREADS;i++)
{
hthread[i] = CreateThread(NULL,0,List,NULL,0,&threadid);
//hthread[i] = HeapAlloc(GetProcessHeap(),HEAP_NO_SERIALIZE,1024*30);
if( hthread[i] == NULL )
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
}
Inside Thread
while(!directories.empty())
{
string path = directories.front();
string spec = path + "\\" + "*";
WaitForSingleObject(Sem,0L);
directories.pop_front();
ReleaseSemaphore(Sem,1,NULL);
HANDLE hfind = FindFirstFileA(spec.c_str(),&ffd);
if(hfind == INVALID_HANDLE_VALUE)
continue;
cout<< path <<endl;;
do
{
if(strcmp(ffd.cFileName,".") && strcmp(ffd.cFileName,".."))
{
if(ffd.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
{
WaitForSingleObject(Sem,0L);
directories.push_front(path + "\\" + ffd.cFileName);
ReleaseSemaphore(Sem,1,NULL);
}
else
{
files.push_back(path + "\\" + ffd.cFileName);
Files++;
}
}
}while(FindNextFileA(hfind,&ffd));
Use following logic for your threads (pseudo-code):
while ( true ) {
lock()
if ( empty ) {
unlock;
sleep;
continue;
} else {
get_one_dir;
remove_that_dir_from_list;
unlock;
}
process_the_dir;
continue;
}
For lock, use a Critical Section, and lock/unlock again when you want to push a new dir in the list.
Use same lock/unlock logic when reading/writing the files vector.
Use critical section for access shared resource:
EnterCriticalSection(&my_section);
//perform data manipulation per-thread
LeaveCriticalSection(&my_section);
Do not forget to initialize the critical section before using.
See this question to get help Problems using EnterCriticalSection

Background Jobs in C (implementing & in a toy shell)

I want to make it so when a user attaches a - after a command it will be executed in the background. For some reason if I execute a command normally it will wait, then if I execute a command in the background it will work but then if I execute a command normally it won't wait for it. I am sure I am just doing something small-ish wrong. Any ideas:
void executeSystemCommand(char *strippedCommand, char *background, int argc, char **args) {
char pathToExecute[80];
// Check if command will be executed in the background
int shellArgs;
bool bg;
if (!strcmp(background, "-")) {
bg = true;
shellArgs = argc -1;
} else {
bg = false;
shellArgs = argc;
}
// Save the linux commands in a new array
char *executableCommands[shellArgs+1];
int j;
for (j = 0; j < shellArgs+1; j++) {
executableCommands[j] = args[j];
}
executableCommands[shellArgs] = NULL;
// Check the $PATH
const char delimiters[] = ":";
char *token, *cp;
char *forLater;
int count = 0;
char *path;
path = getenv("PATH");
// All of this just breaks up the path into separate strings
cp = strdup(path);
forLater = strdup(path);
token = strtok (cp, delimiters);
while ((token = strtok (NULL, delimiters)) != NULL) {
count++;
}
char **argv;
int size = count+1;
argv = (char**) malloc (size);
count = 0;
token = strtok (forLater, delimiters);
argv[0] = (char*) malloc (50);
argv[0] = token;
strcpy(argv[0],token);
while ((token = strtok (NULL, delimiters)) != NULL) {
count++;
argv[count] = (char*) malloc (50);
argv[count] = token;
}
// This goes through the path to see if the linux command they entered
// Ex: sleep exists in one of those files and saves it to a var
int i;
bool weHaveIt = false;
int ac;
for (i = 0; i < count; i++) {
char str[80];
strcpy(str, argv[i]);
strcat(str, "/");
strcat(str, args[0]);
ac = access(str, F_OK);
if (ac == 0) {
weHaveIt = true;
strcpy(pathToExecute, str);
break;
}
}
if (!weHaveIt) {
printf("That is not a valid command. SORRY!\n");
return;
}
executableCommands[0] = pathToExecute;
int status;
// Get the array for
// If user wants command to be a background process
if (bg) {
int background_process_id;
pid_t fork_return;
fork_return = fork();
if (fork_return == 0) {
background_process_id = getpid();
addJobToTable(strippedCommand, background_process_id);
setpgid(0, 0);
execve(executableCommands[0], executableCommands, NULL);
exit(0);
} else {
return;
}
} else {
int background_process_id;
pid_t fork_return;
fork_return = fork();
if (fork_return == 0) {
background_process_id = getpid();
status = execve(executableCommands[0], executableCommands, NULL);
exit(0);
} else {
wait(&status);
return;
}
}
}
The call to wait made for the third job returns immediately because the second job has finished and is waiting to be handled (also called "zombie"). You could check the return value of wait(&status), which is the PID of the process that has exited, and make sure it is the process you were waiting for. If it's not, just call wait again.
Alternatively use waitpid, which waits for a specific process:
/* Wait for child. was: wait(&status) */
waitpid(fork_return, &status, 0);
If you do this you should implement a signal handler for SIGCHLD to handle finished background jobs to prevent the accumulation of "zombie" child processes.
In addition to that, in the background job case, the branch where fork() returns 0 you are already in the new process, so the call to addJobToTable happens in the wrong process. Also, you should check the return values of all the calls; otherwise something may be failing and you don't know it. So the code for running a job in the background should look more like this:
if (fork_return == 0) {
setpgid(0, 0);
if (execve(executableCommands[0], executableCommands, NULL) == -1) {
perror("execve");
exit(1);
}
} else if (fork_return != -1) {
addJobToTable(strippedCommand, fork_return);
return;
} else {
perror("fork"); /* fork failed */
return;
}
Every child process created with fork() will exit when the parent process exits.
if (fork_return == 0) {
/* child process, do stuff */
} else {
/* parent process, exit immediately */
return;
}
Explanation
fork spawns a new process as a child process of the current process (parent). Whenever a process in Unix-like operating systems terminates all of its child processes are going to be terminated too. If they have child processes on their own, then these will get terminated too.
Solution
On most shells you can start a process in background if you add an ampersand & to the end of the line:
myApplication arg1 arg2 arg3 ... argN &