0

Hi all and thanks for your time.

I am trying to parallelise a program which executes some commands and I thought pthreads would be a good option.

But I am running into some issues.

This is where I start the threads:

void timetravel(command_stream_t s)
{

  int *retvals[MAXTHREADS];
  if (s == NULL)
    return;
  if (s->num_commands == 0)
    return;
  int err;
  global_table = create_dependency_table(s);
  //global_command = &s;
  global_command = s;
  int fill = 0;

  for (fill = 0; fill < s->num_commands; fill++)
  {

    global_table.status_table[fill] = 1; //Set all commands to waiting
    // printf("global_table.status_table[i] : %d \n", global_table.status_table[fill]);

  }

  int finished = 0;
  while (finished == 0)

  {
    finished++;
    int threadindex = 0;
    for (threadindex = 0; threadindex < MAXTHREADS; threadindex++)
    {
      err = pthread_create(&(tid[threadindex]), NULL, &parallelexecute, NULL);
      if (err != 0)
        printf("\ncan't create thread :[%s]", strerror(err));
      else
        printf("\n Thread created successfully\n");
    }

    for (threadindex = 0; threadindex < MAXTHREADS; threadindex++)
    {
      pthread_join(tid[threadindex], NULL);
    }

    if (completecheck(global_table) == 0)
    {
      finished = 1;
    }
  }
  //  print_dependency_table(global_table);
  //print_command(global_command->command_array[1]);
}

The dependency table is stored as such

*** DEPENDENCY TABLE ***
 ~x~  ~meh~  ~hello~  ~goodbye~  ~phi~  ~a~  ~gamma~  ~delta~  ~b~  ~c~  ~d~  ~e~  ~f~  ~g~
 1  1  0  0  0  0  0  0  0  0  0  0  0  0
 0  0  1  0  0  0  0  0  0  0  0  0  0  0
 0  0  1  1  1  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  1  1  1  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  1  1  1  1  1  1

for the commands

cat x meh
echo hello
echo -s hello goodbye > phi
touch a < gamma > delta
touch -rx b c d e f g

As "hello" is used in command 2 and 3, 3 is dependent on 2 and so we have

 ~x~  ~meh~  ~hello~  ~goodbye~  ~phi~  ~a~  ~gamma~  ~delta~  ~b~  ~c~  ~d~  ~e~  ~f~  ~g~
 0  0  1  0  0  0  0  0  0  0  0  0  0  0
 0  0  1  1  1  0  0  0  0  0  0  0  0  0

So we will not run 3 before 2

After 2 is run, we set its row to 0, so 3 is no longer dependent on it

I have not implemented blocking of any kind because there are no Write/Write conflicts.

We might have a race condition where there is a read before a write, but that is fine - as it only delays thread execution which is ok.

This is the pthreads program:

void* parallelexecute(void *arg)
{
  //printf("gets to parallel execute stage\n");
  int i;
  //printf("global_table.num_cmds_rows : %d \n",global_table.num_cmds_rows);
  for (i = 0; i < global_table.num_cmds_rows; i++)
  {

    // status 1 = runnable, status 2 = running
    //status 0 = completed successfully, status -1 = unsuccessful
    //printf("global_table.status_table[i] : %d \n",global_table.status_table[i]);

    if (global_table.status_table[i] == 1
        && (check_nth_command(&global_table, i)) == 0)
    {
      global_table.status_table[i] = 2;
      execute_command(global_command->command_array[i], 0);
      printf("execution triggered");
      completed_nth_command(&global_table, i, 0);
      break;
    }
  }
  return NULL;

}

These are my global variables

#define MAXTHREADS 2
pthread_t tid[MAXTHREADS];
 //global variable for dependency pool
parallel_data global_table;
 //global variable for commands
command_stream_t global_command;

But I notice when I try to access global_table from parallelexecute I get all sorts of odd values and I am not sure why.

'global table' is a struct thus:

struct parallel_data
  {
    int** dependency_table;  // the main dependency table
    char** file_reference_key;  // find index by name (use strcmp in a loop)
    int* status_table;  // you know you are done when all the statuses are 0 (none should ever be -1)
    int num_files_cols;  // number of columns/files
    int num_cmds_rows;  // number of rows/commands 
  };

And each thread WRITES only on its row in dependency table, and its row in status_table

I am not quite sure how to proceed.

I am also reasonably certain of the supporting functions correctness.

Any help would be appreciated.

alk
  • 69,737
  • 10
  • 105
  • 255
Avi C
  • 176
  • 1
  • 15
  • Have you tried debugging this at all? What is the back trace for the segmentation fault? – wilx Jul 23 '13 at 19:44
  • Indentation/formatting fail. – Martin James Jul 23 '13 at 19:44
  • 1
    Also, I do not see any synchronization anywhere. Should there not be some mutex or such to synchronize mutating access? – wilx Jul 23 '13 at 19:46
  • I expected read/write race conditions to not be an issue because if a read occurs before the previous thread executes, it does nothing. But if a write occurs before a read, then it might or might not execute. We are not concerned with execution order here. – Avi C Jul 23 '13 at 19:48
  • "*And each thread WRITES only on its row in dependency table, and its row in status_table.*" How do you asure this? – alk Jul 30 '13 at 16:33
  • @alk I am not sure this is an issue - because I explicitly address only those locations for write. Element i will only write over in element i of array A. And the i-th command never runs in parallel with itself. – Avi C Jul 31 '13 at 06:45
  • This `if (global_table.status_table[i] == 1 && (check_nth_command(&global_table, i)) == 0)` is no atomic opertion, it can be interupted just in the middle of anything by another thread! Protect variables accessed concurently! Use a mutex to do so. At least do so to make sure malfunctions do not due to missing protection. If then things work, you could remove the protection to see if it still works, also without the protection. – alk Jul 31 '13 at 17:40

2 Answers2

1

I haven't read your code yet, but I saw "I have not implemented blocking of any kind because there are no Write/Write conflicts", That's a MAJOR red flag to me. If you have Read/Write conflicts, then... well... you have conflicts. That's probably related to the bug. The only time it's valid is if you have std::atomic variables or volatile variables, and a quick CTRL+F says you have neither. Your code is probably not synchronizing at all, and thus threads are never seeing the values that the other threads are writing.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
0

I figured out that my style of passing arguments to the pthreads thread function was incorrect - I shall post the edits I made to the code shortly.

Thank you @mooing-duck , @wilx

Avi C
  • 176
  • 1
  • 15