以下のハッシュ表では,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 までメールすること. 本文には授業の感想を含めること.