Loading ...
Sorry, an error occurred while loading the content.

managing multiple pipes and forks

Expand Messages
  • jshaw10
    I ve been reading the online ocaml book and I have some interest in parallel programming sections. My goal is to learn to use fork and sockets to make multiple
    Message 1 of 3 , Sep 30, 2006
    • 0 Attachment
      I've been reading the online ocaml book and I have some interest in
      parallel programming sections. My goal is to learn to use fork and
      sockets to make multiple parallel threads, and perhaps do something
      with server/client networking. For now I'm just trying to learn how to
      handle multiple client threads in parallel with a server thread, with
      2-way communication between each.

      This simple example works fine:

      let simple_pipe_test () =
      let str = String.make 5 ' ' in
      let (inpipe, outpipe) = Unix.pipe () in
      ignore (Unix.write outpipe "hello" 0 5);
      ignore (Unix.read inpipe str 0 5);
      print_endline str;;

      simple_pipe_test ()

      As expected, it prints "hello" and exits.

      Here's my more ambitious project. It creates n threads (defined by
      threadnum), each associated with its own pipe. I want the server
      thread to be able to send the clients single characters - if they
      receive 'q', they send "quit" back to the server and exit. The server
      then modifies its array of pipes so that later it will know that that
      client no longer is accessible (pipes.(n-1) <- Null). The main loop is
      inside make_threads, and occurs when it receives -1 as its argument.
      However, it seems that no actaul communication via the pipes takes
      place at this point. Any help would be greatly appreciated.

      type channel = Chan of Unix.file_descr * Unix.file_descr | Null

      let test () =
      let threadnum = 2 in
      let client_thread_aux (label,inpipe,outpipe) =
      print_string "starting thread ";
      print_endline (string_of_int label);
      let str = String.make 1 ' ' in
      while true do
      match (Unix.read inpipe str 0 1) with
      0 -> ()
      | _ ->
      match str with
      "q" ->
      print_string "received \"q\", ending thread ";
      print_endline (string_of_int label);
      ignore (Unix.write outpipe "quit" 0 4);
      exit 0
      | _ ->
      print_string "did not receive \"q\" in thread ";
      print_endline (string_of_int label);
      done in
      let client_thread = Unix.handle_unix_error client_thread_aux in
      let server_thread_aux () =
      let str = String.make 4 ' ' in
      let pipes = Array.create threadnum Null in
      let rec makepipes = function
      0 -> ()
      | n when n>0 ->
      print_string "Making pipe ";
      print_endline (string_of_int (n-1));
      let (inpipe,outpipe) = Unix.pipe () in
      pipes.(n-1) <- Chan (inpipe,outpipe);
      makepipes (n-1)
      | _ -> () in
      makepipes threadnum;
      let rec make_threads = function
      -1 ->
      while true do
      for i=0 to threadnum-1 do
      match pipes.(i) with
      Null -> ()
      | Chan (inchan,outchan) ->
      print_string "text to send to the thread ";
      print_string (string_of_int i);
      print_string ": ";
      let outstr = read_line () in
      ignore (Unix.write outchan outstr 0 1);
      match Unix.read inchan str 0 4 with
      0 -> ()
      | 4 -> if str="quit" then
      print_string "received \"quit\" from ";
      print_endline (string_of_int i);
      pipes.(i) <- Null;
      | _ -> ()
      done
      done
      | n when n>(-1) ->
      (
      match pipes.(n) with
      Null -> ()
      | Chan (inpipe,outpipe) ->
      match Unix.fork () with
      0 -> client_thread (n,inpipe,outpipe)
      | id -> make_threads (n-1)
      )
      | _ -> ()
      in make_threads (threadnum-1) in
      let server_thread = Unix.handle_unix_error server_thread_aux in
      server_thread ();;

      test ()
    • Richard Jones
      ... Have you tried looking at using threads and the Event module? If you grab the Adwords Toolkit from http://merjis.com/developers/adwords_toolkit and look
      Message 2 of 3 , Oct 1, 2006
      • 0 Attachment
        On Sat, Sep 30, 2006 at 07:22:46PM -0000, jshaw10 wrote:
        > I've been reading the online ocaml book and I have some interest in
        > parallel programming sections. My goal is to learn to use fork and
        > sockets to make multiple parallel threads, and perhaps do something
        > with server/client networking. For now I'm just trying to learn how to
        > handle multiple client threads in parallel with a server thread, with
        > 2-way communication between each.

        Have you tried looking at using threads and the Event module? If you
        grab the Adwords Toolkit from
        http://merjis.com/developers/adwords_toolkit and look at the file
        adwords_mt.ml you'll see an example of worker threads being created,
        controlled by a single thread which sends out commands using the Event
        module.

        Rich.

        --
        Richard Jones, CTO Merjis Ltd.
        Merjis - web marketing and technology - http://merjis.com
        Internet Marketing and AdWords courses - http://merjis.com/courses - NEW!
        Merjis blog - http://blog.merjis.com - NEW!
      • jshaw10
        Sorry I couldnt get back here earlier - it takes so long for posts to appear. Anyway, I fixed it to work. Here s the working vesion: type pipes = {server_read
        Message 3 of 3 , Oct 1, 2006
        • 0 Attachment
          Sorry I couldnt get back here earlier - it takes so long for posts to
          appear. Anyway, I fixed it to work. Here's the working vesion:

          type pipes =
          {server_read : Unix.file_descr;
          server_write : Unix.file_descr;
          client_read : Unix.file_descr;
          client_write : Unix.file_descr}

          type pipe_tracking = Chan of pipes | Null

          let test () =
          let threadnum = 2 in
          let client_thread_aux (label,inpipe,outpipe) =
          while true do
          Thread.delay (0.1);
          let insize = (Unix.fstat inpipe).Unix.st_size in
          let str = String.make insize ' ' in
          ignore (Unix.read inpipe str 0 insize);
          if str="q" then (
          ignore(Unix.write outpipe "quit" 0 4);
          exit 0;
          )
          done
          in
          let client_thread = Unix.handle_unix_error client_thread_aux in
          let server_thread_aux () =
          let pipes = Array.create threadnum Null in
          let rec makepipes = function
          0 -> ()
          | n when n>0 ->
          let (read,write) = Unix.pipe () in
          let (read2,write2) = Unix.pipe () in
          pipes.(n-1) <- Chan {server_read = read;
          server_write = write;
          client_read = read2;
          client_write = write2};
          makepipes (n-1)
          | _ -> () in
          makepipes threadnum;
          let rec quit_threads = function
          0 -> (
          match pipes.(0) with
          Null -> ()
          | Chan x ->
          ignore (Unix.write x.client_write "q" 0 1);
          )
          | n when n>0 -> (
          match pipes.(n) with
          Null -> quit_threads (n-1)
          | Chan x ->
          ignore (Unix.write x.client_write "q" 0 1);
          quit_threads (n-1)
          )
          | _ -> () in
          let rec make_threads = function
          -1 ->
          let threads_remaining = ref threadnum in
          while !threads_remaining>0 do
          for i=0 to threadnum-1 do
          match pipes.(i) with
          Null -> ()
          | Chan x ->
          let insize = (Unix.fstat x.server_read).Unix.st_size in
          let str = String.make insize ' ' in
          ignore (Unix.read x.server_read str 0 insize);
          if str="quit" then (
          print_string "received \"quit\" from ";
          print_endline (string_of_int i);
          pipes.(i) <- Null;
          threads_remaining := !threads_remaining-1;
          )
          else (
          print_string "text to send to the thread ";
          print_string (string_of_int i);
          print_string ": ";
          let outstr = read_line () in
          match outstr with
          "q" -> ignore (Unix.write x.client_write outstr 0 1);
          | "quit" ->
          quit_threads (threadnum-1);
          exit 0;
          | _ -> ()
          )
          done;
          done;
          exit 0
          | n when n>(-1) ->
          (
          match pipes.(n) with
          Null -> ()
          | Chan x ->
          match Unix.fork () with
          0 -> client_thread (n,x.client_read,x.server_write)
          | id -> make_threads (n-1)
          )
          | _ -> ()
          in make_threads (threadnum-1) in
          let server_thread = Unix.handle_unix_error server_thread_aux in
          server_thread ();;

          test ()
        Your message has been successfully submitted and would be delivered to recipients shortly.