以下のハッシュ表では,hash_get(), hash_find() において, キーに割り当てられたメモリ領域が取得できるが, その領域はその後の操作で修正されるため, 修正が終了するまでその領域をロックし保護する.修正後, hash_release() を呼び出してアンロックする.
hash_make() は,バケットのサイズ bucket_size のハッシュ表を作成する. hash_type はハッシュキーのデータ型が string の場合は,STRING_HASH_KEY を指定し, それ以外の場合は INT_HASH_KEY を指定する.
hash_operate() は,ハッシュ表に登録された全エントリに対する操作であるが, この操作を実行するためには, 全てのエントリのロックが開放されている必要がある.
以下にそれぞれの関数の型と説明を示す.
hash_t *hash_make(int bucket_size, int key_type);bucket_sizeで指定されたバケット数のハッシュ表を作成する. key_typeは,ハッシュキーがstringのときは,STRING_HASH_KEYを 指定し,それ以外は INT_HASH_KEY を指定する.
void **hash_get(hash_t *tbl, char *key);keyとして登録されているハッシュ表のエントリのアドレスを返す. エントリがない場合は作成される.エントリはロックされるため, データ競合なしにその内容を修正,読込みできる.
void **hash_find(hash_t *tbl, char *key);keyとして登録されているハッシュ表のエントリのアドレスを返す. エントリがない場合はNULLが返る.エントリはロックされるため, データ競合なしにその内容を修正,読込みできる.
int hash_release(hash_t *tbl, void **data);hash_getあるいはhash_findでロックしたエントリのロックを解放する.
void *hash_delete(hash_t *tbl, void **dataptr);hash_getあるいはhash_findでロックしたエントリを消去する.
int hash_operate( hash_t *tbl, void (*func)(void *, void **, void *), void *usr_arg);ハッシュ表の全エントリに対し,funcで指定された関数を実行する. funcには引数としてkey,エントリのアドレス,usr_argが渡される.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <pthread.h> #include "ll.h" #include "hash.h" static hash_t *h; void print_entry(void *k, void **d, void *a) { char *key = k; char *data = (char *)*d; printf("<key:%s> <data:%s>\n", key, data); } int main() { void **hash_entry; char *data; /* create a hash table of a string hash key with 1117 buckets */ h = hash_make(1117, STRING_HASH_KEY); /* insert data "1" as a key "first" */ hash_entry = hash_get(h, "first"); *hash_entry = strdup("1"); hash_release(h, hash_entry); /* find a data by a key "first" */ hash_entry = hash_find(h, "first"); assert(hash_entry != NULL); printf("<%s>\n", (char *)*hash_entry); hash_release(h, hash_entry); /* dump every data */ hash_operate(h, &print_entry, NULL); /* remove a data */ hash_entry = hash_find(h, "first"); assert(hash_entry != NULL); data = hash_delete(h, hash_entry); free(data); exit(0); } |
以下はそのmainプログラムである.オプションで -d が指定されない場合, daemon(0, 0)でデーモンとなり,バックグランドで動作し, 標準入出力が利用できなくなるので注意すること.
#define DEFAULT_SERVER_PORT 10000 int main(int argc, char **argv) { char *port_number = NULL; int ch, sock, server_port = DEFAULT_SERVER_PORT; int debug_mode = 0; while ((ch = getopt(argc, argv, "dp:")) != -1) { switch (ch) { case 'd': debug_mode = 1; break; case 'p': port_number = optarg; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (port_number != NULL) server_port = strtol(port_number, NULL, 0); /* server_portでlistenし,socket descriptorをsockに代入 */ sock = open_accepting_socket(server_port); if (!debug_mode) daemon(0, 0); /* * 無限ループでsockをacceptし,acceptしたらそのクライアント用 * のスレッドを作成しプロトコル処理を続ける. */ main_loop(sock); /*NOTREACHED*/ return (0); } |
シグナルを処理するスレッドでは,対象となるシグナルを待ち, シグナルが送信されたら適切な処理を行う.
提出締切は 11/11(水) 20:00とする. 作成したプログラムだけでは無く,考察および実行結果も含めること. サブジェクトを SP7 学籍番号 とし,tatebe _at_ cs までメールすること. 本文には授業の感想を含めること.