1

I am trying to implement a stock exchange using Hoare's monitors.

It has two functions buy() and sell() as follow:

buy(procid, ticker, nshares, limit)
sell(procid, ticker, nshares, limit)

And should print information on buyer id, seller id, ticker, number of shares, and price. And fairness is always satisfied.

The pseudo-code of my solution is as follows, but it's not complete. It basically uses a condition variable queue for each ticker. A seller process is put to sleep on this queue when it sends a sell order to the stock exchange, and a buyer process signals this seller process that it wants to buy if the conditions (matching price limit and number of shares) are satisfied.

monitor SE {
  int available_shares;
  int price;

  sell(procid, ticker, nshares, limit) {
    wait(ticker); // put sell order in ticker queue
    available_shares += nshares;
    price = limit;
    printf("Starting transaction with seller %i", procid);
  }

  buy(procid, ticker, nshares, limit) {
    if (limit <= price && nshares <= available_shares) {
      signal(ticker);
      available_share -= nshares;
      printf("Completing transaction with buyer %i", procid);
      printf("Transacting %i %s shares at %i", nshares, ticker, limit);
    } else {
      wait(ticker); // put buy order in ticker queue
    }
  }
}

Would such an approach be able to handle multiple buy and sell orders for multiple tickers? Or does it lead to a dead-end?

aioobe
  • 383,660
  • 99
  • 774
  • 796
ratsimihah
  • 910
  • 1
  • 9
  • 22
  • It seems to me that this code may lead to a deadlock situation, since you are increasing the available_shares variable after the wait, so the buyer will always fails in the condition and both, seller and buyer, wait forever – ees_cu Apr 29 '13 at 13:33
  • It most likely does. Do you know how I could fix this? Or could you suggest a different implementation to implement such a stock exchange? – ratsimihah Apr 30 '13 at 13:26
  • @ladypada boost `lockfree` should help, but look out for http://stackoverflow.com/questions/14893246/trouble-with-boostlockfreequeue-in-shared-memory-boost-1-53-gcc-4-7-2-cl btw: ty for teaching me about how orders are stored & processed. –  May 19 '13 at 13:22

1 Answers1

2

To solve the deadlock problem I would use two condition variables one for buyers and one for sellers. Each method first modifies available_shares, then signals its own condition variable and finally waits on the other condition variable. Even though, each operation has to recheck the condition about available_shares after it wakes up to complete the transaction or to go to sleep again.

The problem here is that this does not keep track on how much you are buying/selling from/to who. It does not even guarantee that the seller sells all its shares in a transaction. So, in response to your original question I don't see how such an approach would be able to handle multiple buy and sell orders for multiple tickers. I propose this other solution which use a HashTable or dictionary in which each key is a limit and each value is a priority queue or a sorted list ordered by the tickers:

monitor SE {
  int available_shares;
  int price;
  Dictionary<int, SortedList<int, Transac>> Ts;

  sell(procid, ticker, nshares, limit) {
    Transac t = new Transac(procid, nshares, limit);

    Ts[limit].enqueue(ticker, t); //probably you should verify first if the entry is not null 

    available_shares += nshares;

    notifyAll(tickerB);

    while(Ts[limit][ticker] > 0)
      wait(tickerS); 

    printf("Starting transaction with seller %i", Ts[limit][ticker].procid);
  }

  buy(procid, ticker, nshares, limit) {

    int nshares_copy = nshares;

    while(true){
      int cnt = 0;
      List<Transac> tmp = new List<Transac>();
      for(int i = 0; i < Ts.keys.length && cnt < nshares; i++){
          if(Ts.keys[i] <= limit){
            for(int j = 0; j < Ts[Ts.keys[i]].lenght && cnt < nshares; j++){
                cnt += Ts[Ts.keys[i]][j].nshares;
                tmp.add(Ts[Ts.keys[i]][j]);
            }
          }
      }
      if(nshares <= cnt){
          available_share -= nshares;

          foreach(Transac t in tmp){
            int min = min(t.nshares, nshares);
            t.nshares -= min;
            nshares -= min;
          }
          break;
      } else {
          wait(tickerB);
      }
    }

    notifyAll(tickerS);

    printf("Completing transaction with buyer %i", procid);
    printf("Transacting %i %s shares at %i", nshares_copy, ticker, limit);
  }
}

I did this using monitors to follow your initial idea, but I have to say that I don't think this is the best way. I think a more fine-grain lock could give you a better performance (such as locks or atomic operations). Note: The code has not been tested. So, I might have left out some implementation details

Community
  • 1
  • 1
ees_cu
  • 780
  • 1
  • 8
  • 18