Understanding unix child processes that use semaphore and shared memory - c++

I'm going to do my best to ask this question with the understanding that I have.
I'm doing a programming assignment (let's just get that out of the way now) that uses C or C++ on a Unix server to fork four children and use semaphore and shared memory to update a global variable. I'm not sure I have an issue yet, but my lack of understanding has me questioning my structure. Here it is:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define NUM_REPEATS 10
#define SEM_KEY 1111
#define SHM_KEY 2222
int globalCounter = 0;
/***** Test function for confriming a process type ******/
int checkProcessType(const char *whoami)
{
printf("I am a %s. My pid is:%d my ppid is %d\n",
whoami, getpid(), getppid() );
for(int i = 1; i<=3; i++){
printf("%s counting %d\n", whoami, i);
}
return 1;
}
void
int main (void) {
pid_t process_id; // PID (child or zero)
int sharedMemID; // Shared memory ID
int sharedMemSize; // shared memory size
struct my_mem * sharedMemPointer; // pointer to the attached shared memory
// Definition of shared memory //
struct my_mem {
long counter;
int parent;
int child;
};
// Gathering size of shared memory in bytes //
sharedMemSize = sizeof(my_mem);
if(sharedMemSize <= 0){
perror("error collection shared memory size: Exiting...\n");
exit(0);
}
// Creating Shared Memory //
sharedMemID = shmget(SHM_KEY, sharedMemSize, 0666 | IPC_CREAT);
if (sharedMemID < 0) {
perror("Creating shared memory has failed: Exiting...");
exit(0);
}
// Attaching Shared Memory //
sharedMemPointer = (struct my_mem *)shmat(sharedMemID, NULL, 0);
if (sharedMemPointer == (struct my_mem*) -1) {
perror("Attaching shared memory has failed. Exiting...\n");
exit(0);
}
// Initializing Shared Memory //
sharedMemPointer->counter = 0;
sharedMemPointer->parent = 0;
sharedMemPointer->child = 0;
pid_t adder, reader1, reader2, reader3;
adder = fork();
if(adder > 0)
{
// In parent
reader1 = fork();
if(reader1 > 0)
{
// In parent
reader2 = fork();
if(reader2 > 0)
{
//In parent
reader3 = fork();
if (reader3 > 0)
{
//In parent
}
else if (reader3 < 0)
{
// Error
perror("fork() error");
}
else
{
// In reader3
}
}
else if(reader2 < 0)
{
//Error
perror("fork() error");
}
else
{
// In reader2
}
}
else if(reader1 < 0)
{
// Error
perror("fork() error");
}
else
{
// In reader1
}
}
else if(adder < 0 )
{
// Error
perror("fork() error");
}
else
{
// In adder
//LOOP here for global var in critical section
}
}
Just some info of what I'm doing (I think), I'm creating a hunk of shared memory that will contain a variable, lets call it counter that will strictly be updated by adder and by the parent which becomes a subtractor after all child processes are active. I'm still trying to figure out the semaphore stuff that I will be using so adder and subtractor execute in critical section, but my main question is this.
How can I know where I am in this structure? My adder should have a loop that will do some job (update global var), and the parent/subtractor should have a loop for its job (also update global var). And all the readers can look at any time. Does the loop placement for parent/subtractor matter? I basically have 3 locations I know I'll be in parent. But since all children need to be created first does it have to be in the last conditional after my third fork where I know I'm in parent? When I use my test method I get scattered outputs, meaning child one can be after parent's output, then child three, etc. It's never in any order, and from what I understand of fork that's expected.
I really have like three questions going on, but I need to first wrap my head around the structure. So let me just try to say this again concisely without any junk cause I'm hung up on loop and critical section placement that isn't even written up yet.
More directly, when does parent know the existence of all children and with this structure can one child do a task and somehow come back to it (i.e. adder/first child adding to global variable once, exits, and some other child can do its thing etc).
I still feel like I'm not asking the right thing, and I believe this is due to still trying to grasp concepts. Hopefully my stammering will kind of show what I'm stuck on conceptually. If not I can clarify.

Related

POSIX semaphores between parent and child process [duplicate]

This question already has answers here:
How to use POSIX semaphores on forked processes in C?
(2 answers)
Closed 3 years ago.
I want the following output from parent process and child process alternatively
parent : 2 x 1 = 2
child : 2 x 2 = 4
parent : 2 x 3 = 6
.
.
child : 2 x 10 = 20
I've tried the code below using semaphores.
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
sem_t mutex_odd,mutex_even;
int main()
{
int o=1;e=2;
pid_t pid = fork();
sem_init(&mutex_odd,0,1);
sem_init(&mutex_even,0,1);
if(pid>0)
{
while(o<=9)
{
sem_wait(&mutex_even);
printf("parent : 2 x %d = %d\n", o, 2*o);
o+=2;
sem_post(&mutex_odd);
}
}
else if(pid == 0)
{
while(e<=10)
{
sem_wait(&mutex_odd);
printf("parent : 2 x %d = %d\n", e, 2*e);
e+=2;
sem_post(&mutex_even);
}
}
else
{
printf("Child process couldn't be created!\n");
exit(0);
}
return 0;
}
But the output is as shown below. Control just stays there without terminating the program.
parent : 2 x 1 = 2
child : 2 x 2 = 4
Is this a deadlocked state? How to solve this problem?
When a parent process forks, its child inherits a COPY of the values that the parent was managing. A copy doesn't use the same physical memory area; also the memory pointers, although it seems they have the same address value, don't point the same physical memory area.
The way to obtain that the parent and the child share memory is to use IPC (inter process communication) functions.
The program below uses the IPC functions: shmget, shmat to allocate the memory to manage the semaphores (variable mutex) and uses the functions shmdt to "deallocate" the mutex array pointer and smdctl to remove the allocated physicall memory.
An other issue of your code is the initialization of the semaphore. The second parameter (pshared), when the sharing is between forked processes, shall be 1. With the purpose to avoid sync issues the third parameter (value) it's better it's set to 1 for the mutex the parent process waits for and set to 0 for the mutex the child process waits for.
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
static sem_t * mutex;
int main()
{
int o=1,e=2,r;
pid_t pid;
int shmid=0;
shmid=shmget(0,sizeof(mutex)*2 + SHMLBA, IPC_CREAT | SHM_R | SHM_W);
if (shmid==-1) {
perror("shmget");
return errno;
}
mutex=shmat(shmid, NULL, 0);
if (mutex== (void *) -1){
perror("shmat");
return errno;
}
r=sem_init(&mutex[0],1,1);
if (r) {
perror("m0");
return errno;
}
r=sem_init(&mutex[1],1,0);
if (r) {
perror("m1");
return errno;
}
pid=fork();
if(pid>0)
{
while(o<=9)
{
sem_wait(&mutex[0]);
printf("parent : 2 x %d = %d\n", o, 2*o);
o+=2;
sem_post(&mutex[1]);
}
// Waits end of
waitpid(pid,NULL,0); // Waits end of child
puts("End");
r=shmdt(mutex); // Free memory
if (r)
perror("shmdt");
r=shmctl(shmid,IPC_RMID,NULL); // Remove map id.
if (r)
perror("shmctl");
}
else if(pid == 0)
{
while(e<=10)
{
sem_wait(&mutex[1]);
printf("child : 2 x %d = %d\n", e, 2*e);
e+=2;
sem_post(&mutex[0]);
}
}
/*---------------------*/
else
{
perror("Child process couldn't be created!\n");
exit(0);
}
return 0;
}

linux c++ synchronization method both inter and intra process

The question is brought up when I developing a registry system (c/c++, 2.6.32-642.6.2.el6.x86_64 #1 SMP) used to bookmark information for each database, which requires locking for both inter and intra process. Normally, lockf(), flock(), fcntl() are obvious candidates for the inter process locking, but then I find out that they do not work as expected for intra-process locking(multi threads in same process).
I tested it using the following program:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h> /* For O_RDWR */
#include <unistd.h> /* For open(), creat() */
#include <errno.h>
int counter = 0;
void* counterThread(void* ptr)
{
int lockfd = 0;
int tmpCounter = 0;
lockfd = open("/tmp/lockfile.txt", O_CREAT|O_WRONLY, 0666);
if(lockfd == -1)
{
printf("lockfile could not be created, errno:%d\n", errno);
return NULL;
}
if(lockf(lockfd, F_LOCK, 0) == -1)
{
printf("lockfile could not be locked, errno:%d\n", errno);
return NULL;
}
counter++;
tmpCounter = counter;
if(lockf(lockfd, F_ULOCK, 0) == -1)
{
printf("lockfile could not be unlocked, errno:%d\n", errno);
return NULL;
}
close(lockfd);
printf("counter is %d, lockfile is %d\n", tmpCounter, lockfd);
}
int main()
{
int threadNum = 30000;
pthread_t threads[30000];
int i = 0;
int rv = 0;
for(; i < threadNum; i++)
{
rv = pthread_create( &threads[i], NULL, &counterThread, NULL);
if(rv != 0)
{
printf("failed to create pthread %d\n", i);
return -1;
}
}
for(i = 0; i < threadNum; i++)
pthread_join(threads[i], NULL);
return 0;
}
The output would be:
counter is 1, lockfile is 4
counter is 2, lockfile is 3
counter is 3, lockfile is 5
counter is 4, lockfile is 6
counter is 7, lockfile is 4
...
counter is 29994, lockfile is 3
counter is 29995, lockfile is 3
counter is 29996, lockfile is 3
counter is 29997, lockfile is 3
counter is 29998, lockfile is 3
The output sequence is random and sometimes missing some numbers inside, meaning there is definitely a race condition happening. I think the reason is probably that fd opened for the same file in the same process is somehow optimized to be reused. Because all these locking mechanism is implemented in granularity of fd, the locking does not work in this case.
Given the background, I would like to ask the following question:
Is there any means I could force open to return different fd for different threads to same process to make the locking works?
Is there any good practice or convenient API in Linux to do both inter and intra process locking? What I could think of is the following means to implement it(not verified yet), but I would like to know some easier ways:
(1) Implement mutex and semaphore to serialize the access to all these lockfile APIs for the critical resources
(2) shm_open a shared memory, mmap it in different processes and add semaphore/mutex inside to lock the critical resources
Thanks in advance:)

Global variable in fork() child process

I have encountered an issue when trying to make a duplicate check function.
The main objective is to store data from child process (based on the check() function result that returns true or false) to parent process. I already tried global variables but didn't work.
This is my code :
...
for(j=0; j<indIP; j++)
{
fflush(stdout);
if (!(fork()))
{
char* this_ip = strdup(ip[j]);
if(is_duplicate_check(this_ip,"file1"))
{
if(debugLevel >= 2) printf("Duplicate IP %s\n", this_ip);
}
else if( is_duplicate_check(this_ip,"file2"))
{
if(debugLevel >= 2) printf("Duplicate IP %s\n",this_ip);
}
else
{
if(debugLevel >= 2) printf("Checking IP [%d of %d] -> [%s]\n",current_combo,possible_combinations,ip[j]);
checkauth(this_ip);
}
exit(0);
}
else
{
numforks++;
current_combo += trys;
if (current_combo > possible_combinations)
{
break;
}
if (numforks >= maxf)
{
wait(NULL);
numforks--;
}
}
indInterface++;
if(indInterface>=countInterface) indInterface=0;
}
puts("Finalizing...");
while(numforks>0)
{
printf("Waiting for the child processes [%d] are finished ....\n", numforks);
wait(NULL);
numforks--;
}
puts("Script completed!");
return 0;
...
In short the program reads ips from a text file and checks them if they are a certain GEO CODE location. The is_duplicate_check checks if the ip was not already checked, but it is working by storing ips to file1 and file2, and when it arrives on 100.000 records it is making a lot of load.
Now all i want is to store ips from child process in an array and check before calling check() function or not.
I already tried with
static int *glob_var;
glob_var = (int *) mmap(NULL, sizeof *glob_var, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
glob_var++;
printf("glob_var = [%d]\n",glob_var);
allways gives me something like (-1232557773525 ...), no use.
How can i solve this?
A fork duplicates the memory. So when you store the variable it is different memory from the parent process.
If you can use threads you can have the behavior where you share a global variable (because threads share memory).
Or if you have to fork you can look at
How to use shared memory with Linux in C
for shared memory usage or have a look at the boost version:
http://www.boost.org/doc/libs/1_60_0/doc/html/interprocess/sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.sharedmemory

memory leak with sockets and map

I have a socket server, everytime a new connection is made, a XClient class is instantiated and I am inserting it into a map. I am watching the memory usage through task manager. everytime a new connection is made, lets assume, the memory usage of my program increases by 800kb for example. Inside that class, there is a connected variable, which will tell me wheter this client is active or not. I created a thread to run endlessly and iterate through all the elements of my map and I'm checking if the connected variable is true or false. if it is false, I am (at least I think I am...) releasing the memory used by the previously instantiated XClient class. BUT, the memory usage is being decreased only half of the 800kb (for example, no precise values). So, when a client connects: +800kb. when client disconnects: -400kb. I think I have a memory leak? If I have 100 clients connected, that 400kb that is not being released would turn into 4000kb of non-used(?) memory, and that would be a problem.
So, here is my code.
The thread to iterate through all elements:
DWORD Update(XSockets *sockets)
{
while(true)
{
for(sockets->it = sockets->clients.begin(); sockets->it != sockets->clients.end(); sockets->it++)
{
int key = (*sockets->it).first;
if(sockets->clients[key]->connected == false) // remove the client, releasing memory
{
delete sockets->clients[key];
}
}
Sleep(100);
}
return true;
}
The code that is adding new XClients instances to my map:
bool XSockets::AcceptConnections()
{
struct sockaddr_in from;
while(true)
{
try
{
int fromLen = sizeof(from);
SOCKET client = accept(this->loginSocket,(struct sockaddr*)&from,&fromLen);
if(client != INVALID_SOCKET)
{
srand(time(NULL));
int clientKey = rand();
XClient* clientClass = new XClient(inet_ntoa(from.sin_addr),clientKey,client);
this->clients.insert(make_pair(clientKey,clientClass));
}
Sleep(100);
}
catch(...)
{
printf("error accepting incoming connection!\r\n");
break;
}
}
closesocket(this->loginSocket);
WSACleanup();
return true;
}
And the declarations:
map<int,XClient*> clients;
map<int,XClient*>::iterator it;
You've got several problems, but the chief one is that you appear to be sharing a map between threads without any synchronization at all. That can lead to all kinds of trouble.
Are you using c++11 or Boost? To avoid memory leak nightmares like this, you could create a map of shared pointers. This way, you can let the structure clean itself up.
This is how I would do it:
#include <memory>
#include <map>
#include <algorithm>
#include <functional>
#include <mutex>
typedef std::shared_ptr<XClient> XClientPtr;
std::map<int, XClientPtr> client;
std::mutex the_lock;
bool XSockets::AcceptConnections()
{
/* snip */
auto clientClass = std::make_shared<XClient>(/*... params ...*/);
the_lock.lock();
clients[clientKey] = clientClass;
the_lock.unlock();
/* snip */
}
bool client_is_connected(const std::pair<int, XClientPtr> &p) {
return p.second->connected;
}
DWORD Update(XSockets *sockets) {
while(true) { /* You should probably have some kind of
exit condition here. Like a global "running" bool
so that the thread will eventually stop. */
the_lock.lock();
auto it = sockets->clients.begin(), end = sockets->clients.end();
for(; it != end; ) {
if (!it->second->connected)
//Clients will be destructed here if their refcount goes to 0
sockets->clients.erase(it++);
else
++it;
}
the_lock.unlock();
Sleep(100);
}
return 1;
}
Note: Above code is untested. I haven't even tried to compile it.
See What happens to an STL iterator after erasing it in VS, UNIX/Linux?. In your case, you are not deleting everything, so you will want to not use a for loop.
sockets->it = sockets->clients.begin();
while (sockets->it != sockets->clients.end())
{
int key = (*sockets->it).first;
if(sockets->clients[key]->connected == false) // remove the client, releasing memory
{
delete sockets->clients[key];
sockets->clients.erase(sockets->it++);
}
else
{
sockets->it++;
}
}

Linux: Executing child process with piped stdin/stdout

Using Linux and C++, I would like a function that does the following:
string f(string s)
{
string r = system("foo < s");
return r;
}
Obviously the above doesn't work, but you get the idea. I have a string s that I would like to pass as the standard input of a child process execution of application "foo", and then I would like to record its standard output to string r and then return it.
What combination of Linux syscalls or POSIX functions should I use?
I'm using Linux 3.0 and do not need the solution to work with older systems.
The code provided by eerpini does not work as written. Note, for example, that the pipe ends that are closed in the parent are used afterwards. Look at
close(wpipefd[1]);
and the subsequent write to that closed descriptor. This is just transposition, but it shows this code has never been used. Below is a version that I have tested. Unfortunately, I changed the code style, so this was not accepted as an edit of eerpini's code.
The only structural change is that I only redirect the I/O in the child (note the dup2 calls are only in the child path.) This is very important, because otherwise the parent's I/O gets messed up. Thanks to eerpini for the initial answer, which I used in developing this one.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define PIPE_READ 0
#define PIPE_WRITE 1
int createChild(const char* szCommand, char* const aArguments[], char* const aEnvironment[], const char* szMessage) {
int aStdinPipe[2];
int aStdoutPipe[2];
int nChild;
char nChar;
int nResult;
if (pipe(aStdinPipe) < 0) {
perror("allocating pipe for child input redirect");
return -1;
}
if (pipe(aStdoutPipe) < 0) {
close(aStdinPipe[PIPE_READ]);
close(aStdinPipe[PIPE_WRITE]);
perror("allocating pipe for child output redirect");
return -1;
}
nChild = fork();
if (0 == nChild) {
// child continues here
// redirect stdin
if (dup2(aStdinPipe[PIPE_READ], STDIN_FILENO) == -1) {
exit(errno);
}
// redirect stdout
if (dup2(aStdoutPipe[PIPE_WRITE], STDOUT_FILENO) == -1) {
exit(errno);
}
// redirect stderr
if (dup2(aStdoutPipe[PIPE_WRITE], STDERR_FILENO) == -1) {
exit(errno);
}
// all these are for use by parent only
close(aStdinPipe[PIPE_READ]);
close(aStdinPipe[PIPE_WRITE]);
close(aStdoutPipe[PIPE_READ]);
close(aStdoutPipe[PIPE_WRITE]);
// run child process image
// replace this with any exec* function find easier to use ("man exec")
nResult = execve(szCommand, aArguments, aEnvironment);
// if we get here at all, an error occurred, but we are in the child
// process, so just exit
exit(nResult);
} else if (nChild > 0) {
// parent continues here
// close unused file descriptors, these are for child only
close(aStdinPipe[PIPE_READ]);
close(aStdoutPipe[PIPE_WRITE]);
// Include error check here
if (NULL != szMessage) {
write(aStdinPipe[PIPE_WRITE], szMessage, strlen(szMessage));
}
// Just a char by char read here, you can change it accordingly
while (read(aStdoutPipe[PIPE_READ], &nChar, 1) == 1) {
write(STDOUT_FILENO, &nChar, 1);
}
// done with these in this example program, you would normally keep these
// open of course as long as you want to talk to the child
close(aStdinPipe[PIPE_WRITE]);
close(aStdoutPipe[PIPE_READ]);
} else {
// failed to create child
close(aStdinPipe[PIPE_READ]);
close(aStdinPipe[PIPE_WRITE]);
close(aStdoutPipe[PIPE_READ]);
close(aStdoutPipe[PIPE_WRITE]);
}
return nChild;
}
Since you want bidirectional access to the process, you would have to do what popen does behind the scenes explicitly with pipes. I am not sure if any of this will change in C++, but here is a pure C example :
void piped(char *str){
int wpipefd[2];
int rpipefd[2];
int defout, defin;
defout = dup(stdout);
defin = dup (stdin);
if(pipe(wpipefd) < 0){
perror("Pipe");
exit(EXIT_FAILURE);
}
if(pipe(rpipefd) < 0){
perror("Pipe");
exit(EXIT_FAILURE);
}
if(dup2(wpipefd[0], 0) == -1){
perror("dup2");
exit(EXIT_FAILURE);
}
if(dup2(rpipefd[1], 1) == -1){
perror("dup2");
exit(EXIT_FAILURE);
}
if(fork() == 0){
close(defout);
close(defin);
close(wpipefd[0]);
close(wpipefd[1]);
close(rpipefd[0]);
close(rpipefd[1]);
//Call exec here. Use the exec* family of functions according to your need
}
else{
if(dup2(defin, 0) == -1){
perror("dup2");
exit(EXIT_FAILURE);
}
if(dup2(defout, 1) == -1){
perror("dup2");
exit(EXIT_FAILURE);
}
close(defout);
close(defin);
close(wpipefd[1]);
close(rpipefd[0]);
//Include error check here
write(wpipefd[1], str, strlen(str));
//Just a char by char read here, you can change it accordingly
while(read(rpipefd[0], &ch, 1) != -1){
write(stdout, &ch, 1);
}
}
}
Effectively you do this :
Create pipes and redirect the stdout and stdin to the ends of the two pipes (note that in linux, pipe() creates unidirectional pipes, so you need to use two pipes for your purpose).
Exec will now start a new process which has the ends of the pipes for stdin and stdout.
Close the unused descriptors, write the string to the pipe and then start reading whatever the process might dump to the other pipe.
dup() is used to create a duplicate entry in the file descriptor table. While dup2() changes what the descriptor points to.
Note : As mentioned by Ammo# in his solution, what I provided above is more or less a template, it will not run if you just tried to execute the code since clearly there is a exec* (family of functions) missing, so the child will terminate almost immediately after the fork().
Ammo's code has some error handling bugs. The child process is returning after dup failure instead of exiting. Perhaps the child dups can be replaced with:
if (dup2(aStdinPipe[PIPE_READ], STDIN_FILENO) == -1 ||
dup2(aStdoutPipe[PIPE_WRITE], STDOUT_FILENO) == -1 ||
dup2(aStdoutPipe[PIPE_WRITE], STDERR_FILENO) == -1
)
{
exit(errno);
}
// all these are for use by parent only
close(aStdinPipe[PIPE_READ]);
close(aStdinPipe[PIPE_WRITE]);
close(aStdoutPipe[PIPE_READ]);
close(aStdoutPipe[PIPE_WRITE]);