Home > database >  Where to lock and unlock the mutexes?
Where to lock and unlock the mutexes?

Time:10-03

I'm writing a program where there are two threads, the first thread scans an input file(one int per line) and assigns the number to a global variable. The second thread then reads the global variable and if it's even prints it twice to a file and if odd prints it only once.

For example if the input file is:

1
2
3

then the output file should be:

1
2
2
3

Unfortunately what happens is that the output file comes out as:

3

Where can I position my mutex locks and unlocks in order to get the correct result?

Here is my code:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <iostream>
#include <cstdlib>

using namespace std;

FILE* ifile;
int variable = 0;
pthread_mutex_t thing;

struct arguments {
  FILE* file;
};

void* meth1(void* param) {
  ifile = fopen("intput.txt", "r");
  if (ifile == NULL) {
    printf("couldn't open the file");
    return 0;
  }

  pthread_mutex_lock(&thing);
  while (!feof(ifile)) {
    fscanf(ifile, "%d\n", &variable);
  }
  pthread_mutex_unlock(&thing);

  return NULL;
}

void* meth2(void* param) {
  if (variable % 2 == 0) {
    pthread_mutex_lock(&thing);
    fprintf((FILE*)param, "%d\n", variable);
    fprintf((FILE*)param, "%d\n", variable);
    pthread_mutex_unlock(&thing);
  }
  if (variable % 2 != 0) {
    pthread_mutex_lock(&thing);
    fprintf((FILE*)param, "%d\n", variable);
    pthread_mutex_unlock(&thing);
  }

  return NULL;
}

int main() {
  FILE* ofile;

  ofile = fopen("output.txt", "w");
  if (ofile == NULL) {
    printf("couldn't open the file");
    return 0;
  }

  arguments args;
  args.file = ofile;

  pthread_t thread1;
  pthread_create(&thread1, NULL, meth1, NULL);
  pthread_join(thread1, NULL);

  pthread_t thread2;
  pthread_create(&thread2, NULL, meth2, args.file);
  pthread_join(thread2, NULL);

  fclose(ofile);
  pthread_mutex_destroy(&thing);
  return 0;
}

CodePudding user response:

In your for loop you do this:

pthread_mutex_lock(&thing);
while (!feof(ifile)) {
    fscanf(ifile, "%d\n", &variable);
}
pthread_mutex_unlock(&thing);

So, you're consuming the whole file and assigning to the variable on each loop. There is no opportunity for writing anything other than 3.

CodePudding user response:

EDIT:

The following code doesn't directly answer the question but it is a solution to your problem.

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string.h>

using namespace std;

int main() 
{

    fstream f_input;
    fstream f_output;

    /* Open input file */
    f_input.open("input.txt",ios::in);
    if (!f_input.is_open())
    {
        cout << "Unable to open input file" << endl;
        return 0;
    }

    /* Open out file */
    f_output.open("output.txt",ios::out);
    if (!f_output.is_open())
    {
        cout << "Unable to open output file" << endl;
        return 0;
    }

    /* Iterate thru the file per line*/
    string last_line;
    char *p_last_line;
    int  i_last_line_integer;
    unsigned int ui_last_line_len;
    do
    {   
        getline(f_input, last_line);
        p_last_line = (char *)last_line.data();
        sscanf(p_last_line,"%d", &i_last_line_integer);
        ui_last_line_len = last_line.length();

        if (i_last_line_integer %2 == 0) /* it's even, write twice */
        {
            f_output.write(p_last_line,ui_last_line_len);
            f_output.write("\n", ui_last_line_len); 
            f_output.write(p_last_line,ui_last_line_len);
            f_output.write("\n", ui_last_line_len); 
        }
        else    /* it's odd, write once */
        {
            f_output.write(p_last_line,ui_last_line_len);
            f_output.write("\n", ui_last_line_len); 
        }
    }while(!f_input.eof());
    f_input.close();
    f_output.close();
    return 0;
}

OLD:

I see you call the join function immediately after creating the first thread. The join function waits to the thread to end, so if you want both threads to run at once you should use rewrite that section of code to this:

pthread_t thread1, thread2;
pthread_create(&thread1, NULL, meth1, NULL);
pthread_create(&thread2, NULL, meth2, args.file);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);

However I don't think that is what you really want to accomplish, do you want the code to first read the first file and output the numbers into the second file? If so, you could just open both files at once and print into the second file each loop after you read the variable, because your second thread at the moment really only executes once. Now the next code is how you should use the mutexes to prevent variable to be accessed from both threads at once but doesn't fix the algorithm if it's job is to read and copy to another file in case the left over from division is 0:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <iostream>
#include <cstdlib>
using namespace std;
FILE *ifile;
int variable = 0;

pthread_mutex_t thing;
struct arguments
{
    FILE *file;
};

void *meth1(void *param)
{
    
    ifile = fopen("intput.txt", "r");
    if (ifile == NULL)
    {
        printf("couldn't open the file");
        return 0;
    }
    
    while (!feof(ifile))
    {
        pthread_mutex_lock(&thing);
        fscanf(ifile, "%d\n", &variable);
        pthread_mutex_unlock(&thing);
    }
    

    return NULL;
}

void *meth2(void *param)
{

    pthread_mutex_lock(&thing);
    if (variable % 2 == 0)
    {
        fprintf((FILE *)param, "%d\n", variable);
        fprintf((FILE *)param, "%d\n", variable);
    }
    else
    {
        fprintf((FILE *)param, "%d\n", variable);
    }
    pthread_mutex_unlock(&thing);

    return NULL;
}

int main()
{

    FILE *ofile;

    ofile = fopen("output.txt", "w");
    if (ofile == NULL)
    {
        printf("couldn't open the file");
        return 0;
    }

    arguments args;
    args.file = ofile;

    pthread_t thread1, thread2;

    pthread_create(&thread1, NULL, meth1, NULL);
    pthread_create(&thread2, NULL, meth2, args.file);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    fclose(ofile);
    pthread_mutex_destroy(&thing);
    return 0;
}
  • Related