On this page:
Concurrent Programming
Home
8.9

Concurrent Programming

Software Development

From the first day of the semester forward we expect students (you) to visit this page once per 24 hours.

image


Wednesday, April 24th, 2024 2:12:00pm

I pushed a couple small fixes/improvements to the E3 and E4 test harnesses. Make sure to pull periodically to ensure you are using the most up-to-date version.

image

Monday, April 22nd, 2024 11:53:00am

The test harness for milestone E4 is available for your use on github. The repo includes some fresh json configurations in the json-tests directory. Please see the Readme in the repo for instructions on their use.

image

Tuesday, April 16th, 2024 3:39:00pm

The test harnesses for milestones E2 and E3 are available for your use on github. Please see the Readme in each repo for instructions on their use.

Also, the input configurations for milestone E3 didn’t make it into your test results, so (Fixed) here they are.

image

Sunday, April 14th, 2024 9:43:00pm

You may wish to use the provided unit tests as a basic check of your milestone E4 — OTP: Our Terrier Puppies functionality.

image

Friday, April 12th, 2024 9:03:00am

In class we will be taking a look at the language Syndicate. For students that wish to try their hand or play with examples, the instructions below should suffice to get up and running:

image

Wednesday, April 10th, 2024 9:13:00pm

The next milestone is now available—see E4 — OTP: Our Terrier Puppies.

image

Saturday, April 6th, 2024 2:27:00pm

You may wish to use the provided unit tests as a basic check of your milestone E3 — Appointments, Take 2 (and E2 — Adoptions, Take 2) functionality. To run the tests, update the test0 attribute in each file to hold the location, relative to the root of your mix project, of the provided 0-in.json file.

image

Saturday, April 6th, 2024 9:28:00am

I created a repo on the enterprise github with the code from yesterday’s class that you should be able to access here.

image

Thursday, April 4th, 2024 2:27:00pm

The test results for milestone E2 — Adoptions, Take 2 are now available in your repo.

image

Sunday, March 31st, 2024 9:13:00pm

The next milestone is now available—see E3 — Appointments, Take 2.

image

Tuesday, March 26th, 2024 2:04:00pm

I created a repo on the enterprise github with the code from class, that you should be able to access here.

image

Sunday, March 24st, 2024 3:53:00pm

The next milestone is now available—see E2 — Adoptions, Take 2.

image

Friday, March 22nd, 2024 1:18:00pm

For those interested in exploring the performance characteristics, the maximum number of processes in the system may be configured by passing a flag to iex/elixir (which then passes the flag to the underlaying Erlang platform). For example, to set the limit to 10 million processes, launch iex like so:

iex --erl "+P 10000000" -S mix

The code from today’s class is below:

defmodule ConcurrentMapRedux do

  # create a concurrent map server and return its PID

  def new do

    spawn fn -> run_server() end

  end

 

  # send a request to the server and wait for its response

  def map(server, list, function) do

    send server, {:run_map, list, function, self()}

    receive do

      {:result, result} -> result

    end

  end

 

  # Receive map requests and create "middle man" workers to process them

  def run_server do

    receive do

      {:run_map, list, function, reply_to} ->

      spawn fn -> run_map(list, function, reply_to) end

      run_server()

    end

  end

 

  # Create workers for applying the function,

  # collect the results,

  # and send them to reply_to

  def run_map(list, function, reply_to) do

    parent = self()

    for {elem, idx} <- Enum.with_index(list) do

      spawn fn -> worker_fun(elem, idx, function, parent) end

    end

    result = assemble_list length(list), []

    send reply_to, {:result, result}

  end

 

  # Receive :ok messages, accumulating the results

  # expected_results - number of :ok messages to receive

  # accum: results received so far, with their index

  # returns: the resulting list

  def assemble_list expected_results, accum do

    if expected_results == 0 do

      accum

      |> Enum.sort_by(fn {elem, idx} -> idx end)

      |> Enum.map(fn {elem, idx} -> elem end)

    else

      receive do

        {:ok, elem, idx} ->

          assemble_list(expected_results - 1, [{elem, idx} | accum])

      end

    end

  end

 

  def worker_fun(elem, idx, function, parent) do

    send parent, {:ok, function.(elem), idx}

  end

end

image

Tuesday, March 19th, 2024 3:56:00pm

A few followups to today’s lecture:

I updated the IntelliJ setup info (Elixir, Mix) with directions for another way to access the Open Module Settings menu.

Students interested in learning more about the basics of Elixir concurrency may wish to read chapter 15 (specifically, 16.1) of Programming Elixir (Readings). The Elixir section on processes in the Elixir guide is also a useful reference, as well as the additional functions in the standard library’s Process module.

Finally, the bank account module from today’s lecture is reproduced below.

defmodule BankAccount do

 

  def new_account(initial_balance) do

    spawn fn  ->  run_account(initial_balance) end

  end

 

  def run_account(balance) do

    receive do

      {:get, reply_to} ->

        send reply_to, {:balance, balance}

        run_account(balance)

      {:deposit, amount} ->

        run_account(balance + amount)

    end

  end

 

  def get(account) do

    send account, {:get, self()}

    receive do

      {:balance, balance} ->

        balance

    end

  end

 

  def deposit(account, amount) do

    send account, {:deposit, amount}

  end

 

  def run_client(account, tell_done) do

    for _i <- 1..1000 do

      deposit(account, 1)

    end

    send tell_done, :done

  end

 

  def new_client(account, tell_done) do

    spawn fn  -> run_client(account, tell_done) end

  end

 

  def run_demo() do

    account = new_account(0)

    _client1 = new_client(account, self())

    _client2 = new_client(account, self())

    receive do

      :done -> receive do

        :done -> nil

      end

    end

    get account

  end

 

end

image

Sunday, March 17st, 2024 9:37:00pm

The first Elixir milestone is now available—see Elixir Milestones.

image

Friday, March 1st, 2024 6:17:00pm

Students interested in learning more about the Java Memory Model may wish to read chapter 16 (specifically, 16.1) of Java Concurrency in Practice (Readings). This blog post also provides a nice introduction to memory models.

It turns out the Linus quote I was thinking of in class today is from 2002! You can read the thread starting here.

image

Wednesday, February 28th, 2024 12:18:00pm

The description for Milestone 6 — The Doctor Will See You Now has been updated (again) to clarify the desired interaction between day/week rollover and appointment scheduling (see Vet Visits).

image

Monday, February 26th, 2024 2:09:00pm

The description for Milestone 6 — The Doctor Will See You Now has been updated to clarify some aspects of vet behavior (see Life as a Vet).

image

Saturday, February 24th, 2024 1:10:00pm

The interface archive for Milestone 6 — The Doctor Will See You Now has been updated to fix a missing argument to one of the methods.

image

Friday, February 23rd, 2024 12:13:00pm

Students interested in learning more about concurrency and parallelism with respect to performance may wish to read chapter 11 (specifically, 11.1, 11.2, and 11.3) of Java Concurrency in Practice (Readings).

image

Friday, February 23rd, 2024 9:46:00am

The following starter code may come in handy during today’s lecture:

import java.util.Arrays;

import java.util.Comparator;

import java.util.Random;

import java.util.stream.IntStream;

 

public class SeqMergeSort {

 

  public static <T> void sort(T[] items, Comparator<T> comp) {

    sortBetween(items, comp, 0, items.length);

  }

 

  public static <T> void sortBetween(T[] items, Comparator<T> comp, int start, int end) {

    if (end - start <= 1) {

      return;

    }

    var mid = start + (end - start) / 2;

    sortBetween(items, comp, start, mid);

    sortBetween(items, comp, mid, end);

    merge(items, comp, start, mid, end);

  }

 

  public static <T> void merge(T[] items, Comparator<T> comp, int start, int mid, int end) {

    var current1 = start;

    var current2 = mid;

    T[] tmp = (T[]) new Object[end - start];

    for (int i = 0; i < tmp.length; i++) {

      if (current1 == mid) {

        tmp[i] = items[current2++];

      } else if (current2 == end) {

        tmp[i] = items[current1++];

      } else if (comp.compare(items[current1], items[current2]) <= 0) {

        tmp[i] = items[current1++];

      } else {

        tmp[i] = items[current2++];

      }

    }

    System.arraycopy(tmp, 0, items, start, tmp.length);

  }

 

  public static void main(String[] argv) {

    var random = new Random();

    var size = 10_000_000;

    var items = new Integer[size];

    IntStream.range(0, size).forEach(i -> items[i] = random.nextInt(50));

    var startTime = System.nanoTime();

    sort(items, Comparator.naturalOrder());

    var endTime = System.nanoTime();

    var elapsedMillis = (endTime - startTime) / 1e6;

    System.out.println(elapsedMillis);

  }

}

image

Wednesday, February 21st, 2024 4:33:00pm

Milestone 6 — The Doctor Will See You Now is now available.

image

Tuesday, February 20th, 2024 2:03:00pm

The linked archive includes files for testing the producer/consumer queue from today’s lecture:

image

Friday, February 16th, 2024 5:02:00pm

The linked archive includes files for testing the producer/consumer queue from today’s lecture:

Note: Java’s standard library provides the same functionality as our StartupSyncer in the form of a CountDownLatch. You may also be interested in a more general variation, the CyclicBarrier

image

Wednesday, February 7th, 2024 8:25:00pm

Milestone 5 — It’s About Time is now available.

image

Tuesday, February 6th, 2024 12:24:00pm

Students interested in learning more about cancelling tasks and threads may wish to read chapter 7 of Java Concurrency in Practice (Readings).

image

Tuesday, February 6th, 2024 9:51:00am

The following starter code may come in handy during today’s lecture:

public class FileCrawler {

  // search for the needle in each of the passed directories, recursively.

  // the contents of each non-directory file should be searched as a separate (concurrent) task.

  // print the name of the first file found that has a line containing needle.

  // Take care that only one such file name is printed.

  // If no such files are found, print "None found"

  // the program should stop the search as soon as such a file is found.

  // Don't use global variables (i.e. static fields) for communication.

  public static void main(String[] argv) {

    var needle = argv[0];

    // argv[1] ... argv[length - 1] are directory names to search

    for (int i = 1; i < argv.length; i++) {

      var startDir = new File(argv[i]);

      ... start searching in startDir ...

    }

  }

}

You may find the isDirectory and listFiles methods of the File class.

To read the lines in a file, I suggest wrapping a FileReader with a BufferedReader and calling the lines method.

image

Friday, February 2nd, 2024 5:04:00pm

Students interested in learning more about thread pools in Java may wish to read section 6.2 and chapter 8 of Java Concurrency in Practice (Readings).

image

Friday, February 2nd, 2024 3:32:00pm

As mentioned in lecture today, the interfaces and Updated Initialization requirements (method signature) for 4 — Scheduling Veterinary Appointments have been updated to make it easier for milestones 3 and 4 to coexist.

image

Friday, February 2nd, 2024 9:42:00am

The following starter code may come in handy during today’s lecture:

public class ConcurrentMapper {

  private final ExecutorService executorService;

 

  public ConcurrentMapper(ExecutorService executorService) {

    this.executorService = executorService;

  }

 

  public <T,U> Collection<U> map(Collection<T> values, Function<T,U> mapper) {

  }

 

  public static void main(String[] argv) {

    // example usage:

    var mapper = ??;

    var nums = IntStream.range(0, 50).boxed().toList();

    System.out.println(mapper.map(nums, i -> i + 1));

  }

}

image

Thursday, February 1st, 2024 6:25:00am

The test results for milestone 3 — Adopting Pets are now available in your repo.

image

Monday, January 29th, 2024 9:08:00pm

The interfaces interfaces for milestone 4 have been updated for some minor fixes.

image

Saturday, January 27th, 2024 10:29:00pm

Milestone 4 — Scheduling Veterinary Appointments is now available.

image

Friday, January 26th, 2024 8:57:00am

This file for using a ProducerConsumerQueue may come in handy in today’s lecture.

image

Wednesday, January 24th, 2024 1:53:00pm

The provided interfaces for 3 — Adopting Pets were missing one file for defining a PetType. Please use the attached file, again in the com.neu.halp.client package.

image

Tuesday, January 23nd, 2024 2:21:00pm

Below is the implementation of the correct (but gross and horrible) implementation of Account::withdraw from the end of today’s lecture:

    public void withdraw(int amount) {

      lock.lock()

      while (balance < amount) {

        lock.unlock();

        Thread.yield();

        lock.lock();

      }

      balance -= amount;

      lock.unlock()

    }

image

Monday, January 22nd, 2024 11:55:00am

Now that the results of the first programming assignment are available, please see Post-Mortems.

image

Sunday, January 21th, 2024 2:47:00pm

I added some clarifications concerning the intended interactions between client and PetViewer to Milestone 3 — Adopting Pets.

image

Saturday, January 20th, 2024 1:13:00pm

Milestone 3 — Adopting Pets is now available.

image

Friday, January 19th, 2024 9:10:00am

The following starter code may come in handy during today’s lecture:

public class Philosopher implements Runnable {

 

  private final String name;

  private final Fork left, right;

  private final int rounds;

 

  private static final int SLEEP_TIME = 0;

 

  public Philosopher(String name, Fork left, Fork right, int rounds) {

    this.name = name;

    this.left = left;

    this.right = right;

    this.rounds = rounds;

  }

 

  private void think(Random random) throws InterruptedException {

    log("starts thinking");

    Thread.sleep(SLEEP_TIME);

  }

 

  private void log(String message) {

    System.out.println("Philosopher " + name + " " + message);

  }

 

  @Override

  public void run() {

    var random = ThreadLocalRandom.current();

    try {

      for (int i = 0; i < rounds; i++) {

        think(random);

        log("gets hungry");

        eat(random, left, right);

      }

      System.out.println("Philosopher " + name + " finished");

    } catch (InterruptedException ignored) {

    }

  }

 

  protected void eat(Random random, Fork left, Fork right) throws InterruptedException {

    grab(left);

    grab(right);

    Thread.sleep(SLEEP_TIME);

    log("finishes eating");

    release(left);

    release(right);

  }

 

  private void grab(Fork fork) {

    log("reaches for fork " + fork.getName());

    fork.pickUp();

    log("picks up fork " + fork.getName());

  }

 

  private void release(Fork fork) {

    log("puts down fork " + fork.getName());

    fork.putDown();

  }

}

public class Fork {

  private final String name;

 

  public Fork(String name) {

    this.name = name;

  }

 

  public String getName() {

    return name;

  }

 

  private final Lock lock = new ReentrantLock();

 

  public void pickUp() {

    lock.lock();

  }

 

  public void putDown() {

    lock.unlock();

  }

}

public class Main {

  private static final int SIZE = 5;

  private static final int ROUNDS = 10;

  public static void main(String[] argv) {

    var forks = IntStream.range(0, SIZE)

            .mapToObj(i -> new Fork(Integer.toString(i)))

            .toArray(Fork[]::new);

    var philosophers = IntStream.range(0, SIZE)

            .mapToObj(i -> new OrderedPhilosopher(Integer.toString(i), forks[i], forks[(i + 1) % SIZE], ROUNDS) {

            })

            .toArray(Philosopher[]::new);

    var threads = Arrays.stream(philosophers)

            .map(Thread::new)

            .toList();

    var startTime = System.currentTimeMillis();

    threads.forEach(Thread::start);

    try {

      for (var t : threads) {

        t.join();

      }

    } catch (InterruptedException ignored) {

    }

    var finishTime = System.currentTimeMillis();

    System.out.println("Elapsed: " + ((double) (finishTime - startTime)) / 1000);

  }

}

image

Thursday, January 18th, 2024 1:46:00pm

If you are using gson, make sure you are enabling the serializeNulls option of a GsonBuilder when serializing the output.

image

Thursday, January 18th, 2024 10:38:00am

The previous sample tests incorrectly used "CAT" and "DOG" as values for a PetType. The fixed tests can be found at this link.

image

Wednesday, January 17th, 2024 5:12:00pm

You may wish to run your homework solution on these sample tests. Each test case is a pair of files: a JSON input configuration and the expected JSON output.

image

Tuesday, January 16th, 2024 8:02:00am

The following starter code may come in handy during today’s lecture:

public class Account {

  private long balance = 0;

 

  public long getBalance() {

    return balance;

  }

 

  public void deposit(long amount) {

    balance += amount;

  }

}

 

public class Client {

  private String name;

  private Account account;

 

  public Client(String name, Account account) {

    this.name = name;

    this.account = account;

  }

 

  public void work() {

    account.deposit(1);

  }

 

}

 

public class Main {

  public static void main(String[] argv) throws InterruptedException {

    var checking = new Account();

    var teacher = new Client("Sam", checking);

    var sideHustle = new Client("halp.com", checking);

    var t1 = new ClientThread(teacher);

    var t2 = new ClientThread(sideHustle);

    t1.start();

    t2.start();

    System.out.println(checking.getBalance());

  }

}

 

class ClientThread extends Thread {

  private Client client;

 

  public ClientThread(Client client) {

    super();

    this.client = client;

  }

 

  @Override

  public void run() {

    client.work();

  }

}

image

Wednesday, January 10th, 2024 1:37:00pm

Milestone 2 — Warmup: Defining and Working With Data is now available.

image

Monday, January 1st, 2024 2:19:59pm

Welcome to Building Extensible Systems, Spring 2024.

See Abstract for a concise course description.

If you choose to take the course, familiarize yourself with the web site as quickly as possible. Project Milestones will evolve every week. Any out-of-the-ordinary changes will be announced on this front page.

image