Showing posts with label IPC. Show all posts
Showing posts with label IPC. Show all posts

Wednesday, April 22, 2009

CLIPC Semaphores in Action


The Short Story

How the CLIPC Semaphore class can be used to solve the lost update problem.


The Long Story

You can find the source code for CLIPC on SourceForge. The example that I'm showing here can also be found on SourceForge.


The Lost Update: How Not to Run a Bank

Here is some code that implements the bank application described in the previous blog entry on semaphores.

An account is implemented as a text file that contains the balance of the account. Clients use the following process:

  1. Pause for a random period of time
  2. Read the account balance from the file
  3. Pause for a random period of time
  4. Calculate the new balance/decision the withdraw
  5. Write out the new balance to the file

The program randomly decides the amount to deposit/withdraw, with the limitation that it cannot withdraw more money than exists in the account.


public void run(File file, Random r) throws Exception
{
ThreadUtils.sleep(r.nextInt(2000));
int balance = readBalance(file);
sleep(r.nextInt(4000));
int amount = generateTransactionAmount(r, balance);
printMessage(balance, amount);
balance = balance + amount;
writeBalance(file, balance);
}

Here is a screenshot of the app not working quite as desired:



With Semaphores: the Lost Update Found!

By adding a semaphore, the lost update problem can be avoided. The previous process needs to be modified a little bit:
  1. Lock the account (reserve the semaphore)
  2. Read the account balance from the file
  3. Pause for a random period of time
  4. Calculate the new balance/decision the withdraw
  5. Write out the new balance to the file
  6. Unlock the account (release the semaphore)

The modified code:


public void run(Semaphore sem, File file, Random r) throws Exception
{
ThreadUtils.sleep(r.nextInt(2000));
sem.decrement();
int balance = readBalance(file);
sleep(r.nextInt(4000));
int amount = generateTransactionAmount(r, balance);
printMessage(balance, amount);
balance = balance + amount;
writeBalance(file, balance);
sem.increment();
}

The output from the revised sample program:


The code to connect to the semaphore or to create it if it does not already exist is:

 Semaphore(fileName);

The file is an actual file that is used to allow clients to connect to the same semaphore. I'll explain more in the next post.

This code creates a binary semaphore. To create a semaphore that can have a max value of "n" use this call:

 Semaphore(fileName, max value);

For this example, a binary semaphore was used. A command line argument passed the name of the semaphore file.

 sem = new Semaphore(argv[1]);

Conclusion

This posting contained a quick example of how to solve the "Lost Update" problem described in a previous post using a binary semaphore from the CLIPC library. The sample code can be obtained from SourceForge, along with the rest of the CLIPC code.

This example uses file naming for semaphores without really explaining what file naming is or what it is for. In the next exciting chapter of the ongoing CLIPC saga, I will explain how that works.

Thursday, April 16, 2009

Introducing CLIPC


The Short Story

CLIPC is a new open-source java library for IPC. It provides new IPC primitives like semaphores and shared queues, and it makes existing primitives like shared memory easier to use. CLIPC currently supports the Windows and Linux platforms.


The Long Story

CLIPC is the com.lts.ipc library that I wrote because I could not find a Java library that did some Inter-Process Communications (IPC) functions that I was interested in. CLIPC has been the topic of several talks that I have given recently at the Boulder Java Users Group (BJUG) and the Denver Open Source Users Group (DOSUG).

Over the next couple of weeks, I am hoping to create some blog entries about CLIPC and some of the trials and tribulations I went through to write the library. This will be of interest to people who are interested in IPC and also those are are interested in the Java Native Interface (JNI).

CLIPC makes use of JNI because Java does not support certain IPC concepts like Semaphores and FIFOs. This requires the use of JNI to perform the required system calls and whatnot through C, a language that the two platforms that CLIPC currently supports uses.

Another aspect of CLIPC/JNI is that it requires the creation of a consistent interface across multiple platforms. Both Windows and Linux support First-In, First-Out messaging (FIFOs), but the similarities pretty much end there.

For example, on Windows there are Named Pipes. These are always bi-directionaly and function in a lot of ways like very fast TCP/IP connections. Named pipes are represented with files in a special directory.

Linux also supports FIFOs, but on that platform they are uni-directional. They appear to be files on the file system in that there are no naming requirements and they can appear anywhere that regular files can. Linux FIFOs require no special system calls in order to connect to, though they do require special calls to create.

How do you reconcile these differences in order to create a uniform interface to FIFOs? Should they really be more like the named pipes of Windows and allow bi-directional data flow or should they be uni-directional?

I don't know if I made the best decisions possible for CLIPC, but I can talk about why I made the decisions that I did. This will be the topic of future blog entries.