The two parts of this assignment entail producing a simple database server that handles any number of clients. The database contains a number of pairs of names of countries and the names of their capitals. Clients may query it, asking for the capital of a country; they may add new pairs to it and delete pairs from it. Initially, you get a single-threaded, single-client version of the program. You are to modify it in stages, first adding support for multiple clients with multiple threads, then making the database coarse-grained thread-safe, and finally fine-grained thread-safe.
The version of the code provided is in C. Clients interact with the database via xterm windows; youget the windowing code and there is should be no need for you to modify it (checks have been made on linux, mac, and windows with cygwin). Associated with each client window is a thread that handles all the client’s interaction with the database. It waits for input from the client, parses client commands, calls database code as required, and returns results to the client. The database is rather simple — it’s a collection of name-value pairs organized as a binary search tree (but not balanced — making that thread-safe is extremely difficult).
The program’s source consists of six files. The file server.c contains the mainline code of the server; db.c and db.h contains the code that manages the database; window.c, window.h and interface.c contain the code for communicating with and managing the windows.
A single-threaded, single-client version of the program is in hw1Part1. Your assignment is to turn it into a multithreaded program that handles multiple clients. For this part you are only concerned about database queries (not additions or deletions). In part 2 you will deal with the operations that modify the database.
The directory contains a Makefile. Run the command make — it produces an executable called server. Execute server; a window will appear. Within this window, type the command, “f caps”. This initializes the database by running a script contained in the caps file. You can give it queries of the form “q <country>” and it will respond with that country’s capital, if it is in the database. E.g., try “q papua_new_guinea” — note that all letters are lower case and underscores are typed where blanks should be. If a country has a common abbreviation, e.g., usa and uk, the abbreviation is used. Typing a line containing only <control>D in the window causes the client to self-destruct (and for the window to disappear).
You are to modify server.c so that when you start up the program, no window is created automatically. Instead, every time you hit enter (in the window in which you’re running server), a new window is created along with a new thread to handle it. When you type commands into any of the new windows, they should be handled just as in the single-threaded version of the program. However, commands typed into any of the windows access the same, shared database.
Note that the program should be terminated with care: one should first terminate the various client windows (by typing <control>D in them), and only then terminate the main window (by typing <control>D into it. (Fixing this would be an additional third part which will not be assigned.)
In the single-threaded version, the (only) thread calls RunClient — see the code in server.c. In your multithreaded version, you must arrange so that every time enter is typed, rather than the main thread calling RunClient, a new thread is created and detached and it calls RunClient. This shouldn’t require you to write much code, but make sure that you modify Makefile so that the -pthread flag is passed to gcc!
In C a constructor routine mallocs storage and then initializes it. In the single-threaded version of the program, the main routine (in server.c) calls Client_constructor to allocate and initialize an instance of Client_t. It then calls RunClient, passing it the pointer to the Client_t instance, which does the work.
Use the following strategy: modify Client_constructor so that it creates a thread that calls RunClient. Thus each time you hit enter, the main thread simply calls Client_constructor. So main no longer will need to call RunClient.
The file server.c contains the main routine. You need to modify it to support the creation of additional client threads. The window.c file contains the implementation of client windows. Windows are created by calling window_constructor. To communicate with the window, a thread calls the serve method, which sends the answer of the previous query (or the empty string, if there was no previous query) to the window, and waits for and returns the next query. See the code in server.c for an example of how to use these methods.
Note that the only way for the program to cause a window to disappear is to call window_destructor, passing it the handle provided by window_constructor. Client_destructor makes this call: so make sure that client threads call Client_destructor when they terminate!
The db.c file contains the code for parsing commands and the implementation of the database, which is structured as a collection of items of type Node_t.
The interface.c file contains the code that is invoked by xterm to handle the communication between you and the database server. There should be no reason for you to modify this code. (It is not multithreaded code and it runs in a separate process.)