Linux popen and system can not be used in Multithreading? - c

I want to use popen or system in multithreading to execute my program, pass a parameter to the program and get its output. But I found that I use multithreading to call the same time (very long) as a single-threaded call. Is there any good way?
void * _multi_threaded_call(void *arg){
char *param = (char *)arg;
call_my_program(param);
return NULL;
}
//buff is the parameter that my
if(pthread_create(&tid[thread_id], NULL, &_multi_threaded_call, &buff) == -1){
printf("fail to create pthread");
exit(1);
}
if(pthread_join(tid[thread_id] , NULL) == -1){
printf("fail to join pthread");
exit(1);
}
finally, I use popen, I can't stand a long time, Do you have any good ways? thx :)
FILE *fp = popen(cmd, "r");

Related

Popen fails with No file descriptors available

Why does the code below fail after a few seconds?
The error outputs No file descriptors available.
The code runs on a MIPS CPU.
I want to execute a shell command every second and get the result.
static char data[1024];
static void * my_thread(void * arg)
{
while (true)
{
FILE * fp;
fp = popen("ls /", "r");
if (fp == NULL)
{
printf("Error: %s", strerror(errno));
exit(1);
}
while (fgets(data, sizeof(data) - 1, fp) != NULL)
{
printf("%s", data);
}
pclose(fp);
sleep(1);
}
return NULL;
}
Linux kernel version: 4.14.81
EDIT: Maybe I have to mention that there is a fork after the thread is created.

Thread safe file copy

I'm trying to write a program that backs up multiple files to a folder called .backups. It creates one thread for each file or subdirectory, and that thread is responsible for the copy operation. However it's not working correctly. Sometimes files are never copied, sometimes they are but there are 0 bytes, and sometimes it works correctly. It seems completely random and I have no idea what's causing it. Can anyone help me figure it out?
// Copies the file from source to destination and returns number of bytes written
ssize_t copy_file(char* from, char *to)
{
const int BUFFER_SIZE = 4096;
char buffer[BUFFER_SIZE];
ssize_t n;
ssize_t written = 0;
FILE* file_from = fopen(from, "r");
FILE* file_to = fopen(to, "w");
if (file_from == NULL || file_to == NULL)
return -1;
while ((n = fread(buffer, 1, BUFFER_SIZE, file_from)) > 0) {
if (fwrite(buffer, sizeof(char), n, file_to) != n)
return -1;
written += n;
}
return written;
}
// Thread responsible for handling the backup of a single file or subdirectory
void* backup_thread(void* arg)
{
struct backup_info* info = (struct backup_info*) arg;
ssize_t written;
written = copy_file(info->file, info->destination);
int rc = pthread_detach(pthread_self());
if (rc != 0)
exit(EXIT_FAILURE);
free(info);
return NULL;
}
EDIT: Also, this is how I am creating each of the threads.
struct backup_info* info = malloc(sizeof(struct backup_info));
if ((rc = pthread_create(&thread_id, NULL, backup_thread, info)) != 0)
fprintf(stderr, "pthread_create() failed (%d): %s", rc, strerror(rc));
How does the main thread exit?
If it just returns from main(), then that is the same as calling exit(), and will result in all the other threads being unceremoniously killed in the middle of whatever they happen to be doing.
If instead you call pthread_exit() explicitly in main(), then the detached threads will be allowed to finish before the process exits.
Note also that the exit(EXIT_FAILURE) in backup_thread() has the same problem - if that error case fires, it will tear down the entire process immediately. pthread_exit() may be better used here as well.
I spotted something wrong that may be causing your problem. You never call fclose() on any of your files. That will eventually lead to using up all of your file descriptors (which are shared among your threads). I don't know if that is the only thing wrong, but you should make the fix and see what happens.

Test for standard streams piping failed

After creating a function to grab stdin, stdout & stderr, I wanted to test it ..
Here is the test code:
int fd[3];
char *buf = calloc(200, sizeof(char));
FILE *stream;
pid_t pid;
pid = opencmd(fd, "/bin/echo", (char *[]){"/bin/echo", "hello!"});
stream = fdopen(fd[2], "r");
while (fgets(buf, 200, stream) != NULL)
printf("stderr: %s\n", buf);
fclose(stream);
stream = fdopen(fd[1], "r");
while (fgets(buf, 200, stream) != NULL)
printf("stdout: %s\n", buf);
fclose(stream);
free(buf);
closecmd(pid, fd);
This does not manage to work as intended. I spent an hour debugging and could not manage to trace the problem, but as far as I managed to go, I realized that using fdopen to start using the descriptors' streams does not work (for some reason), but using functions that work directly with file descriptors (such as write(2) & read(2)) works fine.
What might be the possible reason for this ?
this excerpt: (char *[]){"/bin/echo", "hello!"}); is missing the final NULL parameter – user3629249

pppd popen hanging in C

I am launching pppd using popen in my program to make obtaining the IP address and interface name a little bit easier. My code runs fine independently and is a pretty typical implementation. The problem begins when it runs in the full program (too large to post)... the loop seems to hang for quite a while at the fgets() line. The popen is launched in its own thread that is then managed based on the output.
The popen/pppd code is essentially the following.
int main(void){
pthread_create(&thread, NULL, pppd, (char *)NULL);
pthread_join(thread, NULL);
return 0;
}
void *pppd(char *args){
char* command = malloc(32);
sprintf(command, "pppd %s call %s", dev, provider);
pppd_stream = popen(command, "r");
if(pppd_stream == NULL){
pppd_terminated = TRUE;
return;
}
free(command);
while(fgets(buffer, 128, d->pppd_stream) != NULL){
//handle_output
}
}
CPU usage isnt a problem, the system and the other parts of the program are still responsive and running as expected.
Any thoughts on what could be causing this slow down?
Ensure that your command is null terminated string:
#define COMMAND_BUFFER_SIZE 256 /* Modify this if you need */
snprintf(command, COMMAND_BUFFER_SIZE, "pppd %s call %s", dev, provider);
command[COMMAND_BUFFER_SIZE - 1] = '\0';
pppd_stream = popen(command, "r");
EDIT:
Check your fgets:
while(fgets(buffer, 128, d->pppd_stream) != NULL){
You may want this:
while(fgets(buffer, 128, pppd_stream) != NULL){

Pthread Mutex locking

I have a basic question on mutext handling.
I have a file which appears at 2 other threads(out of 3). I need to mutually exclude access to it by a thread. So I do the following in a function called from the thread1 handler:
int sub_routine_thread1{
pthread_mutex_lock(&mut)
FILE *fp;
fp = fopen("myfile", "r");
if(fp == NULL){
return -1;
}
pthread_mutex_unlock(&mut)
return 0;
}
As you can see I already know that if the file pointer return a NULL, then my mutex gets locked here and the unlocking never happens. So I changed it to the following:
int sub_routine_thread1{
pthread_mutex_lock(&mut)
FILE *fp;
fp = fopen("myfile", "r");
if(fp == NULL){
pthread_mutex_unlock(&mut)
return -1;
}
pthread_mutex_unlock(&mut)
return 0;
}
But after this though I have a bad feeling this is not the way mutex locking should be done. I chanced upon something about cleanup handlers and perhaps thought this is how I must code:
int sub_routine_thread1{
pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);
pthread_mutex_lock(&mut);
FILE *fp;
fp = fopen("myfile", "r");
if(fp == NULL){
return -1;
}
pthread_cleanup_pop(1);
return 0;
}
Is this the right way? Can you please clarify?
But after this though I have a bad feeling this is not the way mutex loxking should be done.
Yes it is. Your second example is perfectly fine. pthread_cleanup_push is used to run functions when the thread is cancelled, that's not what you should use here.
Allthough, I'd probably prefer to do something like
int sub_routine_thread1() {
FILE *fp;
int ret = -1;
pthread_mutex_lock(&mut)
fp = fopen("myfile", "r");
if(fp != NULL){
//do_stuff_unlocked(fp);
ret = 0;
}
pthread_mutex_unlock(&mut)
return ret;
}
First of all
if(fp == NULL){
return -1;
pthread_mutex_unlock(&mut); /* This is never reached. */
}
if(fp == NULL){
pthread_mutex_unlock(&mut); /* Probably what you want. */
return NULL;
}
Second, cleanup handlers are really really cool and useful, but they are only called when you cancel the thread using pthread_cancel. They are not called when the thread exits normally (and that return is considered normal).

Resources