Perl: Value of global variable not getting updated when changed in child - perl

Code Snippet:
my $kill=0;
my #array1 = ("abc", "def","ghi");
&runSmokesAndMonitor;
sub runSmokesAndMonitor {
foreach my $smokeTestVarDirName (#array1) {
if ($pid =fork()) {
print "parent\n"; ### Have some other action items as well here in parent
}
else {
$kill++;
print "Value of kill is $kill\n";
exit 0;
}
}
}
Here, I am getting output:
parent
Value of kill is 1
parent
Value of kill is 1
parent
Value of kill is 1
Required/Expected: (As $kill is global variable, so values of $kill must have updated wherever new value would have assigned)
parent
Value of kill is 1
parent
Value of kill is 2
parent
Value of kill is 3
parent
Why is the output not as expected, and how can i achieve it?

A child created by fork is a new process with its own address space. Global variables are per process only, not global per user or per system or even global between all instances of a software running in the world. That's why changes to a global variable are only reflected in the current process.
If you need to share information between processes you need IPC (inter process communication), i.e. things like sockets, pipes, shared memory etc - see perlipc for more. There are ways to make sharing variables across processes easier, like IPC::Shareable.

Related

is there an abnormal way to terminate a child process to get certain outputs in this code?

i'm new to operating systems and i found this code , and i don't understand why certain outputs like : abc , we can't get
suppose we have this code in c :
int main()
{
if(fork()==0)
printf("a");
else
{
printf("b");
waitpid(-1);
}
printf("c");
return 0;
}
waitpid() waits for a child process to terminate.
can the child process be terminated in abnormal way ? so that we can have this outputs : abc, bc ?
according to at least the linux manpage for fork:
RETURN VALUE
On success, the PID of the child process is returned in the parent, and
0 is returned in the child. On failure, -1 is returned in the parent,
no child process is created, and errno is set appropriately.
so if your child program isn't ever created the entire output will be c for the parent process and nothing for the child process, because it never came to be.
Also it is possible that the parent process is killed before it can output a, or c, then you'll only get the child's output, bc. or maybe the parent is killed before it can even fork! there are lots of possibilities and with good timing (and some calls to the sleep function inbetween) you could probably reproduce them.

How many total number of processes are there?

Yesterday, i had a interview and i was asked this question of code snippet using fork() .
void main()
{............
for (int k=1;k<=10;k++)
{
pid[k]=fork();
if(!pid[k])
execvp(.....);
}
}
According to my understanding, i told 1024 total processes will be there including the parent as 2^n -1 = 1023 + 1 parent where n = total forks
But, the interviewer replied that my answer was wrong.
What is wrong with my understanding?
Given this code
pid[k]=fork();
if(!pid[k])
execvp(.....);
and reading the man page of fork which states that
On success, the PID of the child process is returned in the parent,
and 0 is returned in the child.
we know that the child process will perform the exec call (and go on executing a different program), whereas the parent will loop and create another child.
This means that a child will be created for each iteration of the loop, in this case 10 times. So, the answer is 10 children + 1 parent = 11.
Now, if the program that gets started by exec is the same program, the fun will stop only when the computer's memory is exhausted: on every iteration 10 programs will each create 10 children, which each will create 10 children, and so on. A pecularity of fork() is that parent and child get an image of the same variables (which would lead to a predictable number of children, ie some figure related to a power of 2), obviously this isn't true when a program gets exec'd, which means that available memory will be the only limit.

Is there a way to get screen to return a session id or pid?

Is there a way to get screen to echo back the session id when it creates a new window?
I am working on script in perl and I need screen to return the session id or the PID to me so I record it in an array or a hash.
What is your purpose for gathering these pids? It can be a little tricky in perl. Something like Unix::PID might help ( http://metacpan.org/pod/Unix::PID ) but I have the suspicion that your question does not address the actual problem you are trying to solve.
Since you are using screen -dmS <somename> you can do this:
my %screens;
for( $i = 0; $i < 10; $i++) {
system("screen -dmS server$i");
}
open(my $fh, "screen -list|");
while (<$fh>){
if (/Detached/) {
/\s*(\d*)\.(.*?)\s/;
my ($pid, $name) = ($1, $2);
$screens{$name} = $pid;
}
};
Check for the environment variable $ENV{'STY'} within any programs running inside screen.
On my MacOS X 10.6 system at least, it contains the session ID, e.g.:
29379.ttys000.hostname
and where the first field is the PID.
From outside screen, you can run:
screen -list
to get a list of all of your sessions.
Failing that, it's unclear how you're actually starting screen from within your script, but if you use a standard fork / exec model then the child PID available after the call to fork will be the required PID. See man perlipc for more details on how to fork a child program and interact with it.

Cannot Run Fork, unwanted number of processes are forked

I am having an issue with Fork in Perl. I want to execute 10 Fork Processes at a go from one single script all 10 Child (Forked) processes will do the same thing (Copy files from one place to another).
When I execute this code, my OS Hangs and when I actually check there are hell lot of processes which are forked at a time.
Here is my Code:
while ($callCount <= $totalCalls) {
for (1..$TotalProcessToFork) {
print "Call -> $callCount";
if($pid = fork) {
#in Parent Process
print " :: PID -> $pid\n";
push(#list_of_pid, $pid);
} else {
#in Child Process
`touch $callCount`;
}
$callCount++;
}
}
Now when I execute this code, there are around 1000 child processed which are executed.
Can any one tell me what wrong I am doing here.
The children fork, too. You need to exit the loop one way or another in the child case. A common pattern is to fork and exec, or you could just say last.
This happens because when you fork a process, it creates two processes. Lets call them a1 and a2. Now a1 is the parent and a2 is the child, so when a2 is executed, it creates b1 and b2. When these all are executed, they also create new processes recursively.
You may want to take a look at Parallel::ForkManager, which will probably make your life easier.
Also, don't use external Linux touch command; it's better to use File::Touch.

Interprocess Mutex In Perl

I have a Perl CGI program that executes under mod_perl. Within the program, I would like to prevent a resource from accessing by multiple processes at the same time.
# Semaphore Initialization Code
# 10023 is unique id, and this id will be same across different apache process.
# 1, Only one semaphore being created.
# 0722, as all process will be execute under apache account. Hence, they will all having '7' privilege.
my $sem = new IPC::Semaphore(10023, 1, 0722 | IPC_CREAT); # Code(1)
# Set 0th (one and only one) semaphore's value to 1, As I want to use this semaphore as mutex.
$sem->setval(0, 1); # Code(2)
The problem is :
How can I make Code(1) create a new semaphore ONLY when the semaphore if the 10023 id has never being created before, either by same process or other processes?
How can I execute Code(2) ONLY the first time I create the semaphore with 10023 id? A semaphore shall be only initialized ONE TIME.
Another approach is to create an empty file for locking purpose. However, this will end up of having thousands of temporary files.
link text
Adding the IPC_EXCL flag causes the underlying semget to either create a new semaphore or fail. You can use this to get the effect you want.
This should work for you:
#Attempt to create (but not get existing) semaphore
my $sem = IPC::Semaphore->new(10023, 1, 0722 | IPC_CREAT | IPC_EXCL);
if ($sem) {
#success, semaphore created, proceed to set.
print "new semaphore\n";
$sem->setval(0, 1);
}
else {
#obtain the semaphore normally
print "existing semaphore\n";
$sem = IPC::Semaphore->new(10023, 1, 0722); #no IPC_CREAT here
die "could not obtain semaphore?" unless $sem;
}