Pthread Mutex locking - c

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).

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.

Critical Section Synchronization C

Trying to implement the critical section of this program to actually swap between both threads correctly as stated later in the description.
I am trying to do a problem for my Operating Systems course. The problem is that I need to input two files, one of each are put into their separate threads, they will read through the file till they hit a line with the number "0". Then the other thread is supposed to run by the same rules.
This program is supposed to take two file input and figure out the message by concatenating both of the inputs from the files in a specific order and then printing out the output after it has deciphered it.
The inputs of these two files as shown below
Person1 Person2
--------- ----------
t 0
0 h
i 0
s 0
0 i
0 s
0 a
t 0
e 0
0 s
t 0
the above inputs should result in a string with this output
Example: “thisisatest”
Currently what is going wrong with the assignment is that it is not swapping correctly between the two threads and sitting in infinite loops.
Like I said above I am trying to solve this assignment by use of Mutexes and Pthreads
Below is the current implementation of my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static char *charArray[1000];
void *threadPerson1(void *value){
FILE *fPTR;
char buffer[2];
char *fileName = "Person1.txt";
fPTR = fopen(fileName, "r");
if (fPTR == NULL){
printf("was unable to open: %s\n", fileName);
return NULL;
}
while(1){
//Entering the critical section
pthread_mutex_lock(&mutex);
fscanf(fPTR, "%s", buffer);
printf("This is Person1: %s\n", buffer);
if(buffer != "0"){
charArray[count] = buffer;
count++;
}
if(buffer == "0"){
pthread_mutex_unlock(&mutex);
}
//exiting the critical section
}
}
void *threadPerson2(void *value){
FILE *fPTR;
char buffer[2];
char *fileName = "Person2.txt";
fPTR = fopen(fileName, "r");
if (fPTR == NULL){
printf("was unable to open: %s\n", fileName);
return NULL;
}
while(1){
//entering the critical section
pthread_mutex_lock(&mutex);
fscanf(fPTR, "%s", buffer);
printf("This is Person2: %s\n", buffer);
if(buffer != "0"){
charArray[count] = buffer;
count++;
}
if(feof(fPTR)){
printf("read end of file of: Person2\n");
fclose(fPTR);
return NULL;
}
if(buffer == "0"){
pthread_mutex_unlock(&mutex);
}
//exiting the critical section
}
}
int main(int argc, char **argv){
pthread_t thread1;
pthread_t thread2;
pthread_create(&thread1, NULL, threadPerson1, NULL);
pthread_create(&thread2, NULL, threadPerson2, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
for(int x = 0; x < 1000; x++){
if(charArray[x] == NULL){
printf("\n");
break;
}else{
printf("%s", charArray[x]);
}
}
return 0;
}
At least two things are incorrect in your program. First of all, if one thread releases the mutex, you are not guaranteed that the scheduler will allow the other thread will run, the releasing thread may very well go on and reacquire the mutex right away. Use a condition variable, read its manpages. Also, here are some examples, in particular 4-8: Multithreaded programming guide
Two, when you reach end of file, you need to release the mutex to clean up. Easiest way to do it is what we call RAII in C++, i.e. use a resource handle that releases the mutex when the handle object goes out of scope. You can do similar things in C e.g. by registering a cleanup function, or a 'goto' to end of function with cleanup code called from there.

Linux popen and system can not be used in Multithreading?

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");

file locking not working as expected in C

I have a file which will be read and write by the multiple process. So to synchronize the file between multiple processes I was using fcntl().
Let's assume we have a file orignal.txt and we have some content in the orignal.txt. Assume the contents in the file are:
show core status
show table status
show action status
Now let's say we have three process A,B,C which would be accessing orignal.txt for deleting the content from it. Say A will delete show core status. B will delete show table status and C will delete show action status.
Actually show core status,show table status and show action status are some commands which is related to particular process, So I am assuming show core status is related to A so whenever A will come he will write show core status into the file orignal.txtand before A terminates it will delete the show core status from the file orignal.txt. Same with other processes also.
So for that I have written the code.
Note: This is a common API for deleting the content from the file which all three processes (A,B,C) will use.
#define ACQUIRE_LOCK 1
#define RELEASE_LOCK 0
int delete_content_from_file(char *command)
{
FILE *fp, *tempFd;
char buf[4096];
int ret;
fp = fopen ("orignal.txt", "r+");
if (fp == NULL)
{
printf("orignal.txt does not exist");
return -1;
}
printf("Acquiring lock for orignal.txt");
ret = fileSync(fp,ACQUIRE_LOCK,F_WRLCK);
if(ret == -1)
{
printf("Failed to acquire lock");
exit(EXIT_FAILURE);
}
tempFd = fopen ("duplicate.txt", "w");
if (tempFd == NULL)
{
printf("Duplicate.txt not exist");
return -1;
}
// read text until newline
while (!feof(fp))
{
if (fgets (buf, sizeof(buf), fp) != NULL)
{
buf[strlen(buf)-1]='\0';
if ((ret = strcmp (command, buf)) != 0) {
fprintf(tempFd, "%s\n", buf);
}
}
fclose(tempFd);
system("cp duplicate.txt orignal.txt");
remove("duplicate.txt");
printf("Releasing lock");
ret = fileSync(fp,RELEASE_LOCK,F_UNLCK);
if(ret == -1)
{
printf("unable to release the lock for orignal.txt");
return -1;
}
fclose (fp);
return 0;
}
int fileSync(FILE *fd,bool flag,short lock_type)
{
struct flock lock;
lock.l_type = lock_type;
lock.l_whence = SEEK_SET; // Starting from the begining of the file
lock.l_start = 0; // no offset
lock.l_len = 0; // to the end of file. 0 means EOF
if(flag == ACQUIRE_LOCK)
{
if(fcntl(fileno(fd), F_SETLKW, &lock) < 0)
{
perror("Error to acquire lock");
return -1;
}
}
else
{
if(fcntl(fileno(fd), F_UNLCK, &lock) < 0)
{
perror("Error releasing lock");
return -1;
}
}
return 0;
}
What I expected : When A will release the lock, the content of the file should become
show table status
show action status
and when B will release the lock, the content of the file should become
show action status
and when C will release the lock, the file will become empty.
But
What I got: When A has released the lock, content of the file is same. All three lines are present. But When B has released the lock , I saw B has deleted the content show table status from the file and same C also deleted the show action status
This is not fixed behaviour, sometimes B does not delete the content but A deletes or C deletes.
I have got struck at this point. Looks to me that file is not getting sync between processes. Any help will be appreciated. Thanks in Advance!

Open function : how to protect against directory opening?

I am using the open function like this in my file to get some coordinates from a file :
t_coo *get_buffer(char **av, t_coo **head)
{
int ret;
int fd;
char *line;
int y;
t_coo *cur;
cur = NULL;
*head = NULL;
y = 0;
ret = 0;
fd = open(av[1], O_RDONLY);
while ((ret = get_next_line(fd, &line) > 0))
{
head = get_map(line, head, y);
y++;
}
close(fd);
cur = *head;
return (cur);
}
It is working perfectly but the problem is when I try to make it open a directory, my program segfault. I want to protect it against directory opening so that I dont segault anymore. I tried to look at the flags on the internet and tried many of them but I could not find this one. Can anybody tell me which one it is? Thank you.
You need to use the lstat function to tell you whether the given file name represents a regular file or a directory.
struct stat statbuf;
int rval;
rval = lstat(argv[1], &statbuf);
if (rval == -1) {
perror("error getting file status");
exit(1);
}
if (S_ISREG(statbuf.st_mode)) {
printf("%s is a regular file\n", argv[1]);
} else if (S_ISDIR(statbuf.st_mode)) {
printf("%s is a directory\n", argv[1]);
} else {
printf("%s is something else\n", argv[1]);
}
I would suggest to open the file (which could be a directory) so get a file descriptor, then use fstat(2) on that file descriptor (and check the result of fstat by using statresult.st_mode & S_IFMT == S_IFDIR ...)
This would avoid an (improbable) race condition with the lstat (or stat) then open approach (suggested in Dbush's answer): some other process might (with very bad luck) remove or rename the file between these two system calls. You might also opendir or else open (but that also suffers from a similar race condition).
PS. The race conditions I am suggesting here are so improbable that we can normally ignore them... But they might be a security flaw (than an attacker could use)

Resources