I compiled and install a new version of the kernel and now I have to make the new kernel support two new primitives, I explain more below
I have this file, mysystemcalls-test.c where I get the process and do forks in a for iteration. This is my test file.
//mysyscalls-test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <mysyscalls.h>
#define NCHILDREN 10
int main()
{
int pids[NCHILDREN], i;
int original_parent = getpid();
printf ("before fork: current number of children: %ld\n", getnchildren(1));
for (i=0; i<NCHILDREN; i++) {
pids[i] = fork();
if (pids[i] == 0) {
while (getppid() == original_parent);
exit(0);
}
}
printf("after fork: current number of children: %ld\n", getnchildren(1));
for(i=0; i<NCHILDREN; i++)
printf("pids[%d]:%d\tgetcpid(%d,1):%ld\n" ,i,pids[i],i,getcpid(i,1));
return 0;
}
The real problem is in the second file, mysyscalls.h I can't make the right call for the child process.
//mysyscalls.h
long getnchildren (int debug){
int children;
children = pids[i];
return children;
}
long getcpid (int order, int debug){
int childrenid;
childrenid = getpid();
return childrenid;
}
I don't know how to call these pids in the mysyscalls.h file. I searched and tested some code that I found here but I don't have an exact answer for my problem. I wrote that code but isn't working, it return the same pid.
It's supposed that long getnchildren returns the number of child processes that the calling process has, at the moment the primitive is called.
long getcpid returns the pid of the child of the calling process, at position order in the list of its children.
Get your own pid with getpid.
Iterate through all directories in /proc that start with a digit.
For each such directory, open the status file.
Read all the lines until you find the PPid line.
If the PPid matches the value from getpid, add this directory name to your array.
That will get you the IDs of every process whose parent process is this process.
This outlines a simple way to do some common functions involving for PIDs. If I were you, I would circumvent trying to do this in C. More trouble than its worth, IMO.
#!/bin/bash
# getting children generally resolves nicely at some point
get_child() {
echo $(pgrep -laP $1 | awk '{print $1}')
}
# recursively getting parents isn't that useful,
# so single use function
get_parent() {
echo $(ps -o ppid= -p 36700)
}
get_children() {
__RET=$(get_child $1)
__CHILDREN=
while [ -n "$__RET" ]; do
__CHILDREN+="$__RET "
__RET=$(get_child $__RET)
done
__CHILDREN=$(echo "${__CHILDREN}" | xargs | sort)
echo "${__CHILDREN}"
}
get_children $1
FILE *fp;
char path[1024];
char command[1024];
sprintf(command, "/bin/bash /get_pids.sh %d", getpid());
fp = popen(command, "r");
while (fgets(path, sizeof(path), fp) != NULL) {
// children are listed here
printf("%s", path);
}
pclose(fp);
I've been trying to cook up an unholy one-liner for David Schwartz's method, but I think it is a fully cursed solution. Some other bash-abuser can take a crack at it.
Related
I have a small program in which there're a parent process and two child processes. First, the parent process sends data through pipe to its children (childA, childB). To make it clearer, I have a pointers array which has elements pointing to a struct (Rabbit). The parent process filters this array and sends the filtered data to childA and the same for childB except this data will differ. Then childA and childB does something with its data and send it back to the parent process. I have to implement it with pipes. What's wrong with this code snippet and how can I solve this problem?
int pipefd_a[2];
int pipefd_b[2];
pid_t child_a, child_b;
if (pipe(pipefd_a) == -1) {
perror("Error during opening pipe A!");
exit(EXIT_FAILURE);
}
if (pipe(pipefd_b) == -1) {
perror("Error during opening pipe B!");
exit(EXIT_FAILURE);
}
child_a = fork();
if (child_a == 0) { // Child A
close(pipefd_a[1]);
Rabbit rabbit;
while (read(pipefd_a[0], &rabbit, sizeof(Rabbit))) {
// Do something
}
close(pipefd_a[0]);
} else {
child_b = fork();
if (child_b == 0) { // Child B
close(pipefd_b[1]);
Rabbit rabbit;
while (read(pipefd_b[0], &rabbit, sizeof(Rabbit))) {
// Do something
}
close(pipefd_b[0]);
} else {
Rabbit** rabbits_a = (Rabbit**)malloc(sizeof(Rabbit*) * size);
...
// Filter, count_a will be the size of the filtered array
close(pipefd_a[0]);
for (unsigned i = 0; i < count_a; ++i) {
Rabbit rabbit = {rabbits_a[i]->name, rabbits_a[i]->district, rabbits_a[i]->part_count};
write(pipefd_a[1], &rabbit, sizeof(Rabbit));
}
...
// The same for B
...
fflush(NULL);
wait(NULL);
}
}
At a quick glance, it looks like you're on the right track, but you're missing some code in the child processes to write the processed data back to the pipe so it can be picked up by the parent process. Furthermore, your wait() call should probably be the very first call in the parent process after your calls to fork(), because you have no guarantee that the child processes will run before the parent process. Also, you might want to set up some sort of loop structure so that you wait until both child processes terminate prior to trying to read from their pipes.
So, your program structure might look like this:
// #include <sys/stat.h>
#include <unistd.h>
// ...
// ... assuming there's code you didn't show that writes the initial data to the pipes to get it into the children processes...
child_a = fork();
if (child_a == 0) {
// Read from pipe, do stuff, and write to pipefd_a[1] (so you can't close it)
} else {
child_b = fork();
if (child_b == 0) {
// read from pipe, do stuff, and write to pipefd_b[1]
} else {
// Wait for both child processes to end
pid_t pids[] = {child_a, child_b};
pid_t returned_pid;
int i;
for (i = 0; i < 2; i++) {
// the wait() call will return the pid of the process that
// caused wait() to terminate. Since you forked off two processes
// wait could either return child_a or child_b, and we
// want to make sure both processes are finished prior to
// trying to read stuff from their pipes, hence the outer
// for loop
// Update: I realized that if the process is already dead,
// then the do-while loop just runs forever, so I'm throwing in a check
// to make sure the process is alive before starting the loop
struct stat dummy;
char buf[70];
// Every running process on a UNIX system has a corresponding
// ID number and a corresponding subdirectory within the /proc
// directory, so if the directory doesn't exist, the process doesn't exist either
// sprintf(buf, "/proc/%d", pids[i]);
// ---------------------------------------
// Edited again because I'm dumb and forgot
// /proc doesn't exist on macOS (which is what I'm on).
// If you're there, then you can do something like this, which I'll explain below.
sprintf(buf, "ps -e | awk '{ print $1 }' | grep %d", pids[i]);
int result = system(buf);
// If on Linux you can do...
/*
if ( stat(buf, &dummy) < 0 ) {
// Process is dead, continue
continue;
} */
// If on a UNIX system (mac or Linux)...
if (result != 0) {
// Process is dead, continue
continue;
}
do {
returned_pid = wait(NULL);
} while (returned_pid != pids[i]);
}
// At this point, both child processes have terminated, so NOW
// we can read from the pipes
// Read from pipefd_a[0]
// Read from pipefd_b[0]
}
}
So, what the heck is this string: `ps -e | awk '{ print $1 }' | grep %d`
This is a string of three shell commands:
ps -e - this will print information about all currently running processes. This includes the process IDs
awk '{ print $1 }' - this runs an awk script that prints only the first field in a given string, where fields are delimited by whitespace
grep %d - this will search the given file (stdin in this case) for the PID provided (because this is in a format string, %d gets replaced with a process ID)
Then, the system command runs entire string. A return value of 0 means that the command string was executed successfully, meaning that the process ID was found in the list of currently running processes.
Anyway, I hope you're able to get some valuable info from this post.
Here is a C program which operates finding specific properties like CPU bus info by consecutive calls of lshw (to access total hardware list with respective properties) and grep (to select just a relevant point among lshw results):
char *strCombine(char *str1, char *str2, int n)
{
int i = strlen(str2);
int j = 0;
if((str2 = (char *) realloc(str2, (i + n + 1))) == NULL)
perror(0);
while(j < n && str1[j])
{
str2[i] = str1[j];
i++;
j++;
}
str2[i] = 0;
return (str2);
}
int main()
{
pid_t parent;
char buf[1000] = {0};
char *str;
char *argv[6] = {"/usr/bin/lshw", "-C", "CPU", "|", "grep", "bus info"};
int fd[2];
int ret;
if(pipe(fd) == -1)
{
perror(NULL);
return -1;
}
parent = fork();
if(parent == 0)
{
close(fd[1]);
while((ret = read(fd[0], buf, 1000)))
str = strCombine(buf, str, ret);
close(fd[0]);
}
else
{
close(fd[0]);
execv(argv[0], argv);
close(fd[1]);
wait(0);
}
wait(0);
printf("%s", str);
return 0;
}
In this code grep is expected to follow lshw since both go executed by invoking execv. However, this pipeline doesn't work because lshw usage reference gets printed out in terminal (running on Ubuntu 18.04 LTS) instead of bus info needed originally. What makes this program failed to show just info that matters and what way must I try to set up pipeline?
The vertical bar is not a parameter you use to separate commands, as the execve(2) system call will load a program into the virtual space of one process only. You need to create two processes, one per command you want to execute, and communicate them so input from one goes to output from the other. I think also you'll be interested in the output of the last command, so you need to do two redirections (one from the first command to the second, and one from the output of the second command to a pipe descriptor), two forks, and two exec's in order to do this.
First the good news, you can do all this stuff with a simple call to popen(3) without the nitty gritties of making forks and execs while redirecting i/o from individual commands. Just use this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "/usr/bin/lshw -C CPU | grep 'bus info'";
int n = 0;
char line[1000];
/* f will be associated to the output of the pipeline, so you can read from it.
* this is stated by the "r" of the second parameter */
FILE *f = popen(cmd, "r");
if (!f) {
perror(cmd);
exit(EXIT_FAILURE);
}
/* I read, line by line, and process the output,
* printing each line with some format string, but
* you are free here. */
while (fgets(line, sizeof line, f)) {
char *l = strtok(line, "\n");
if (!l) continue;
printf("line %d: [%s]\n", ++n, l);
}
/* once finished, you need to pclose(3) it. This
* makes program to wait(2) for child to finish and
* closing descriptor */
pclose(f);
}
If you need to mount such a pipeline you'll end having to
redirections from first command to second, from second to
parent process, and fork/exec both processes yourself.
In this approach, you handle a subshell to do the piping
and redirection work for you, and just you get a FILE * descriptor to read upon.
(if I find some time, I'll show you a full example of a chain of N commands with redirections to pipe them, but I cannot promise, as I have to write the code)
NOTE
fork() returns the pid of the child process to the parent, and 0 to the child process itself. I don't understand why you have a variable named parent where you store the value received from fork(). If it is nonzero (and non-negative) it represents the pid of a child process. You need two, as you need two processes. In the example I post, you create three processes (you ask a subshell to mount the pipeline for you, so you have a subshell you instruct to create two more processes, to execute your command) If you had to mount all this paraphernalia, you'd also to wait(2) for the children to finish (this is done in pclose(3) call)
I have a little program to spawn a process (only one) repeatedly, while overprinting its output in the same place. I use it as some kind of htop program when I try to see e.g. the output of ls -l (showing a file growing as it is being filled) or the output of df command. It starts the program, makes one fork, redirects the output of it to a pipe and gets the output of the command to count the number of lines output (to emit an escape sequence to put the cursor on top of the listing, and to emit a clear to the end of line after each output line, so shorter lines dont get blurred by longer ones. It shows you how to deal with forks and exec system calls, and you can use as example on how to do the things the brave way. But having popen(3) I think is the solution to your problem. If you want to have a look to my cont program, just find it here.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
FILE *file;
file = fopen(argv[1], "r");
char buf[600];
char *pos;
pid_t parent = fork();
if(parent == 0) {
while (fgets(buf, sizeof(buf), file)) {
pid_t child = fork();
if(child == 0) {
/* is there a function I can put here so that it waits
once the parent is exited to then run?*/
printf("%s\n", buf);
return(0);
}
}
return(0);
}
wait(NULL);
return(0);
}
The goal here to print out the line of a file all at the same time, parallel.
For example:
Given a file
a
b
c
$ gcc -Wall above.c
$ ./a.out file
a
c
b
$ ./a.out file
b
c
a
As in the processes ran at the exact same time. I think I can get this to work if there was a wait clause that waits for the parent to exit then start running the child. As shown in the comments above. Once the parent exits then all the processes would start at the print statement as wanted.
If you had:
int i = 10;
while (i > 0)
{
pid_t child = fork();
if(child == 0) {
printf("i: %d\n", i--);
exit(0);
}
}
then the child processes are running concurrently. And depending on the number of cores and your OS scheduler, they might even run literally at the same time. However, printf is buffer, so the order in which the lines appear on screen cannot be determined and will vary between executions of your program. And because printf is buffered, you will most likely not see lines overlapping other other. However if you were using write directly to stdout, then the outputs might overlap.
In your scenario however, the children die so fast and because you are reading
from a file (which might take a while to return), by the time the next fork is executed,
the previous child is already dead. But that doesn't change the fact, that if
the children would run long enough, they would be running concurrently and the
order of the lines on screen cannot be determined.
edit
As Barmar points out in the comments, write is atomic. I looked up in my
man page and in the BUGS section it says this:
man 2 write
According to POSIX.1-2008/SUSv4 Section XSI 2.9.7 ("Thread Interactions with Regular File Operations"):
All of the following functions shall be atomic with respect to each other in the effects specified in POSIX.1-2008 when they operate on regular files or symbolic links: ...
Among the APIs subsequently listed are write() and writev(2). And among the effects that should be atomic across threads (and pro‐
cesses) are updates of the file offset. However, on Linux before version 3.14, this was not the case: if two processes that share an
open file description (see open(2)) perform a write() (or writev(2)) at the same time, then the I/O operations were not atomic with
respect updating the file offset, with the result that the blocks of data output by the two processes might (incorrectly) overlap.
This problem was fixed in Linux 3.14.
Sever years ago I observed this behaviour of write on stdout with concurrent
children printing stuff, that's why I wrote that with write, the lines may
overlap.
I am not sure why you have an outer loop. You could rewrite as follows. Once you create the child processes, they could run in any order. So you might seem the output in "order" but in another run you might see different order. It depends on the process scheduling by your OS and for your purpose, it's all running in "parallel". So you really don't need to ensure parent process is dead.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
if (argc != 2) {
printf("Incorrect args\n");
exit(1);
}
char buf[1024];
FILE *file = fopen(argv[1], "r");
while (fgets(buf, sizeof buf, file)) {
pid_t child = fork();
if(child == 0) {
write(STDOUT_FILENO, buf, strlen(buf));
_exit(0);
}
}
/* Wait for all child processes. */
while (wait(NULL) != -1);
}
This is fairly simple application which creates a lightweight process (thread) with clone() call.
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#define STACK_SIZE 1024*1024
int func(void* param) {
printf("I am func, pid %d\n", getpid());
return 0;
}
int main(int argc, char const *argv[]) {
printf("I am main, pid %d\n", getpid());
void* ptr = malloc(STACK_SIZE);
printf("I am calling clone\n");
int res = clone(func, ptr + STACK_SIZE, CLONE_VM, NULL);
// works fine with sleep() call
// sleep(1);
if (res == -1) {
printf("clone error: %d", errno);
} else {
printf("I created child with pid: %d\n", res);
}
printf("Main done, pid %d\n", getpid());
return 0;
}
Here are results:
Run 1:
➜ LFD401 ./clone
I am main, pid 10974
I am calling clone
I created child with pid: 10975
Main done, pid 10974
I am func, pid 10975
Run 2:
➜ LFD401 ./clone
I am main, pid 10995
I am calling clone
I created child with pid: 10996
I created child with pid: 10996
I am func, pid 10996
Main done, pid 10995
Run 3:
➜ LFD401 ./clone
I am main, pid 11037
I am calling clone
I created child with pid: 11038
I created child with pid: 11038
I am func, pid 11038
I created child with pid: 11038
I am func, pid 11038
Main done, pid 11037
Run 4:
➜ LFD401 ./clone
I am main, pid 11062
I am calling clone
I created child with pid: 11063
Main done, pid 11062
Main done, pid 11062
I am func, pid 11063
What is going on here? Why "I created child" message is sometimes printed several times?
Also I noticed that adding a delay after clone call "fixes" the problem.
You have a race condition (i.e.) you don't have the implied thread safety of stdio.
The problem is even more severe. You can get duplicate "func" messages.
The problem is that using clone does not have the same guarantees as pthread_create. (i.e.) You do not get the thread safe variants of printf.
I don't know for sure, but, IMO the verbiage about stdio streams and thread safety, in practice, only applies when using pthreads.
So, you'll have to handle your own interthread locking.
Here is a version of your program recoded to use pthread_create. It seems to work without incident:
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#define STACK_SIZE 1024*1024
void *func(void* param) {
printf("I am func, pid %d\n", getpid());
return (void *) 0;
}
int main(int argc, char const *argv[]) {
printf("I am main, pid %d\n", getpid());
void* ptr = malloc(STACK_SIZE);
printf("I am calling clone\n");
pthread_t tid;
pthread_create(&tid,NULL,func,NULL);
//int res = clone(func, ptr + STACK_SIZE, CLONE_VM, NULL);
int res = 0;
// works fine with sleep() call
// sleep(1);
if (res == -1) {
printf("clone error: %d", errno);
} else {
printf("I created child with pid: %d\n", res);
}
pthread_join(tid,NULL);
printf("Main done, pid %d\n", getpid());
return 0;
}
Here is a test script I've been using to check for errors [it's a little rough, but should be okay]. Run against your version and it will abort quickly. The pthread_create version seems to pass just fine
#!/usr/bin/perl
# clonetest -- clone test
#
# arguments:
# "-p0" -- suppress check for duplicate parent messages
# "-c0" -- suppress check for duplicate child messages
# 1 -- base name for program to test (e.g. for xyz.c, use xyz)
# 2 -- [optional] number of test iterations (DEFAULT: 100000)
master(#ARGV);
exit(0);
# master -- master control
sub master
{
my(#argv) = #_;
my($arg,$sym);
while (1) {
$arg = $argv[0];
last unless (defined($arg));
last unless ($arg =~ s/^-(.)//);
$sym = $1;
shift(#argv);
$arg = 1
if ($arg eq "");
$arg += 0;
${"opt_$sym"} = $arg;
}
$opt_p //= 1;
$opt_c //= 1;
printf("clonetest: p=%d c=%d\n",$opt_p,$opt_c);
$xfile = shift(#argv);
$xfile //= "clone1";
printf("clonetest: xfile='%s'\n",$xfile);
$itermax = shift(#argv);
$itermax //= 100000;
$itermax += 0;
printf("clonetest: itermax=%d\n",$itermax);
system("cc -o $xfile -O2 $xfile.c -lpthread");
$code = $? >> 8;
die("master: compile error\n")
if ($code);
$logf = "/tmp/log";
for ($iter = 1; $iter <= $itermax; ++$iter) {
printf("iter: %d\n",$iter)
if ($opt_v);
dotest($iter);
}
}
# dotest -- perform single test
sub dotest
{
my($iter) = #_;
my($parcnt,$cldcnt);
my($xfsrc,$bf);
system("./$xfile > $logf");
open($xfsrc,"<$logf") or
die("dotest: unable to open '$logf' -- $!\n");
while ($bf = <$xfsrc>) {
chomp($bf);
if ($opt_p) {
while ($bf =~ /created/g) {
++$parcnt;
}
}
if ($opt_c) {
while ($bf =~ /func/g) {
++$cldcnt;
}
}
}
close($xfsrc);
if (($parcnt > 1) or ($cldcnt > 1)) {
printf("dotest: fail on %d -- parcnt=%d cldcnt=%d\n",
$iter,$parcnt,$cldcnt);
system("cat $logf");
exit(1);
}
}
UPDATE:
Were you able to recreate OPs problem with clone?
Absolutely. Before I created the pthreads version, in addition to testing OP's original version, I also created versions that:
(1) added setlinebuf to the start of main
(2) added fflush just before the clone and __fpurge as the first statement of func
(3) added an fflush in func before the return 0
Version (2) eliminated the duplicate parent messages, but the duplicate child messages remained
If you'd like to see this for yourself, download OP's version from the question, my version, and the test script. Then, run the test script on OP's version.
I posted enough information and files so that anyone can recreate the problem.
Note that due to differences between my system and OP's, I couldn't at first reproduce the problem on just 3-4 tries. So, that's why I created the script.
The script does 100,000 test runs and usually the problem will manifest itself within 5000-15000.
I can't recreate OP's issue, but I don't think the printf's are actually a problem.
glibc docs:
The POSIX standard requires that by default the stream operations are
atomic. I.e., issuing two stream operations for the same stream in two
threads at the same time will cause the operations to be executed as
if they were issued sequentially. The buffer operations performed
while reading or writing are protected from other uses of the same
stream. To do this each stream has an internal lock object which has
to be (implicitly) acquired before any work can be done.
Edit:
Even though the above is true for threads, as rici points out, there is a comment on sourceware:
Basically, there's nothing you can safely do with CLONE_VM unless the
child restricts itself to pure computation and direct syscalls (via
sys/syscall.h). If you use any of the standard library, you risk the
parent and child clobbering each other's internal states. You also
have issues like the fact that glibc caches the pid/tid in userspace,
and the fact that glibc expects to always have a valid thread pointer
which your call to clone is unable to initialize correctly because it
does not know (and should not know) the internal implementation of
threads.
Apparently, glibc isn't designed to work with clone if CLONE_VM is set but CLONE_THREAD|CLONE_SIGHAND are not.
Your processes both use the same stdout (that is, the C standard library FILE struct), which includes an accidentally shared buffer. That's undoubtedly causing problems.
Ass everyone suggests: it really seems to be a problem with, how shall I put it in case of clone(), process-safety? With a rough sketch of a locking version of printf (using write(2)) the output is as expected.
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#define STACK_SIZE 1024*1024
// VERY rough attempt at a thread-safe printf
#include <stdarg.h>
#define SYNC_REALLOC_GROW 64
int sync_printf(const char *format, ...)
{
int n, all = 0;
int size = 256;
char *p, *np;
va_list args;
if ((p = malloc(size)) == NULL)
return -1;
for (;;) {
va_start(args, format);
n = vsnprintf(p, size, format, args);
va_end(args);
if (n < 0)
return -1;
all += n;
if (n < size)
break;
size = n + SYNC_REALLOC_GROW;
if ((np = realloc(p, size)) == NULL) {
free(p);
return -1;
} else {
p = np;
}
}
// write(2) shoudl be threadsafe, so just in case
flockfile(stdout);
n = (int) write(fileno(stdout), p, all);
fflush(stdout);
funlockfile(stdout);
va_end(args);
free(p);
return n;
}
int func(void *param)
{
sync_printf("I am func, pid %d\n", getpid());
return 0;
}
int main()
{
sync_printf("I am main, pid %d\n", getpid());
void *ptr = malloc(STACK_SIZE);
sync_printf("I am calling clone\n");
int res = clone(func, ptr + STACK_SIZE, CLONE_VM, NULL);
// works fine with sleep() call
// sleep(1);
if (res == -1) {
sync_printf("clone error: %d", errno);
} else {
sync_printf("I created child with pid: %d\n", res);
}
sync_printf("Main done, pid %d\n\n", getpid());
return 0;
}
For the third time: it's only a sketch, no time for a robust version, but that shouldn't hinder you to write one.
As evaitl points out printf is documented to be thread-safe by glibc's documentation. BUT, this typically assumes that you are using the designated glibc function to create threads (that is, pthread_create()). If you do not, then you are on your own.
The lock taken by printf() is recursive (see flockfile). This means that if the lock is already taken, the implementation checks the owner of the lock against the locker. If the locker is the same as the owner, the locking attempt succeeds.
To distinguish between different threads, you need to setup properly TLS, which you do not do, but pthread_create() does. What I'm guessing happens is that in your case the TLS variable that identifies the thread is the same for both threads, so you end up taking the lock.
TL;DR: please use pthread_create()
I want from parent program (called daemon) to start 5 child processes of test program with args(all 5 in parallel, not to wait to finish).
I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char* argv[]){
//missing irrelevant part where argum is set
int status,i;
char cmd[512];
pid_t process_id = 0;
for (i=0; i<=5;i++)
{
process_id = fork();
if (process_id < 0)
{
printf("fork failed - %d!\n",i);
continue;
}
else if(process_id > 0) {
printf("process_id of child process %d \n", process_id);
}
else
{
sprintf(cmd,"./test %s",argum);
status = system(cmd);
exit(0);
}
}
return 0;
}
it starts them but when I run ps -aux to see the processes, besides the good ones (like: ./test [args]) there are some duplicates like: sh -c ./test [args]
How can I get rid of those starting with "sh -c" ?
Instead of calling system() from the child, use a member of the exec*() family of functions.
Calling execXYZ() from the fork()ed off child process replaces the child process by the new process created from what had been passed to the execXYZ() call.
Please note that if execXYZ() succeeds it does not return.
Example for executing /bin/ls -alrt *.c:
The execl*() members of the family expect each white-space separate command line option as a single parameter.
execl("/bin/ls", "ls", "-alrt", "*.c", (char*) 0);
execlp("ls", "ls", "-alrt", "*.c", (char*) 0);
The execv*() members of the family expect each white-space separate command line option in the way parameters are passed to main():
char * const argv[] = {
"ls",
"-alrt",
"*.c",
NULL,
}
execv("/bin/ls", argv);
execvp("ls", argv);
The exec*p() family members make use of the environment's variable PATH to search for the binary to be executed. So for this example (as for the system command ls) the path does need to be specified.
At test program:
#include <unistd.h>
#include <stdio.h>
/* This should list the current working directory. */
int main(void)
{
execl("/bin/ls", "ls", "-al", "-rt", (char*) 0);
perror("execl() failed");
return 0;
}
The simplest way to lose sight of the sh -c entries is:
sprintf(cmd, "exec ./test %s", argum);
The exec replaces the shell run by system() with the command, instead of having the shell hang around until the ./test process terminates.
The alternative is outlined by alk in his answer — use the exec*() family of functions (system calls).