| Latest 5 days | |
| Last Modified : | 11/17 22:42 |
| Total Access : | |
| Today Access : | |
| Your Access : | COOKIE_TIMES: deprecated in static mode. |
| Schedule | |
|---|---|
|
|
|
| TODO | |
|
1.5.4にシテミマシタ。
さあ容量が尽きるまでいくか。
サトームセンのパソコン館でSANWA SUPPLYのワイヤレスLANセット
LAN-WL11SETを17800円+税で買った。
アクセスポイントをハブにつないで電源を入れて、PCカードを
Linuxノートにさし込んだらすぐに使えた。
Windowsではドライバを入れるのに苦労した。
だってドライバがCD-ROMに入ってるんだもん。
PCカードさしたらCD-ROMが使えないのに。。。
アクセスポイントはなるべく下に置くことにした。
上半面だけしか電波が飛ばないみたいからだ。
まあ天上にさかさまにつけてもいいだろうけど。
アクセスポイント管理ツールがWindows専用なのは唯一のマイナス。
まあ自分で独自プロトコルを解析すればいいんだろうけど。
ブラウザでアクセスできればいいのにね。
サンワサプライのLinuxページ
Emacsつかってプログラムを書いているのに補完を知らない人が多い。
「
M-/」です。
ちなみにとっても賢いインデントはTABね。
debian sidにkernel-2.4.10登場。
さっそくアップデート。
debianのカーネル2.4はinitrdがcramfs(Compresed RAM File System?)になっていて、
起動時に/initrdにマウントできるパッチが当たっています。
だからide-diskやext2、reiserfsなどもモジュールでOKなんです。
もちろんcramfsはカーネルに組み込まれているわけですが。
kernel.org
などからダウンロードしたものをdebianで使うには/をマウントするのに最低限
必要なものはカーネルに組み込まなくてはいけないでしょう。
つまり、ディスクを認識するドライバ(ATAPI-IDEの場合ide-disk)と
ルートファイルで使っているファイルシステムのドライバ(ext2とかreiserfsとか)
をモジュールではなく組み込む必要があるでしょう。
最近、apt-getでインストールに失敗するなどで
/var/lib/dpkg/availableや/var/lib/dpkg/statusがこわれてしまう
ことが多い。等間隔で文字のコードが+1されていたりと、
こわれ方に規則性があるのでたぶんdpkgのバグだろうか。
初めはテキストエディタで該当個所を修正していたが、
なんとdselect(apt-getでもaptitudeでもなく)で直るではないか。
dselectの中で[U]pdateしたらこれらのファイルは正しくなります。
dselectなんてslink以降もう使わないだろうと思っていた。
でもdpkgがなおるまでまた何回もお世話になるだろうな。
やはりANSI-Cプログラミングでいちばんめんどうなのはエラー処理だ。
つぎはブロック先頭でしかできない変数宣言。
クラスはなくてもいいから、この2つだけでも克服したISO-Cがいいなあやっぱり。
あとCがC++より楽なのはやはりvoid*か。キャストが要らないから。
つぎはglibにしようか、でもglibは大きいしなあ。。。
そのまえにzlib(もちろんgzreadとかgzwriteとか)にしようか。。。
うーん、getoptとかregexとかも抑えておきたい気もする。。。
waitと通知。タイムアウトを指定する場合は pthread_cond_timedwaitを、 複数スレッドのwaitに対し通知する場合は pthread_cond_broadcastを使えばいい。
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int wait_count;
int counter;
pthread_mutex_t mutex;
pthread_cond_t cond;
} NotifyObject;
void* run_wait(void* arg);
void* run_notify(void* arg);
NotifyObject* newNotifyObject(int wait_count);
void destoryNotifyObject(NotifyObject* obj);
int main(int argc, char* argv[])
{
NotifyObject* obj;
pthread_t wait_thread;
int i;
obj = newNotifyObject(100);
pthread_create(&wait_thread, NULL, &run_wait, obj);
sleep(1);
for (i = 0; i < obj->wait_count; i++) {
pthread_t notify_thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(¬ify_thread, &attr, &run_notify, obj);
}
pthread_join(wait_thread, NULL);
destoryNotifyObject(obj);
puts("main exit");
return 0;
}
NotifyObject* newNotifyObject(int wait_count)
{
NotifyObject* obj;
obj = malloc(sizeof(NotifyObject));
obj->wait_count = wait_count;
obj->counter = 0;
pthread_mutex_init(&(obj->mutex), NULL);
pthread_cond_init(&(obj->cond), NULL);
return obj;
}
void destoryNotifyObject(NotifyObject* obj)
{
pthread_mutex_destroy(&(obj->mutex));
pthread_cond_destroy(&(obj->cond));
free(obj);
}
void* run_wait(void* arg)
{
NotifyObject* obj = arg;
int i;
int ret;
ret = pthread_mutex_lock(&(obj->mutex));
if (ret != 0) {
return (void*) -1;
}
for (i = 0; i < obj->wait_count; i++) {
while (obj->counter == 0) {
ret = pthread_cond_wait(&(obj->cond), &(obj->mutex));
if (ret != 0) {
pthread_mutex_unlock(&(obj->mutex));
return (void*) -1;
}
}
obj->counter--;
puts("consume");
}
pthread_mutex_unlock(&(obj->mutex));
return NULL;
}
void* run_notify(void* arg)
{
NotifyObject* obj = arg;
int ret;
ret = pthread_mutex_lock(&(obj->mutex));
if (ret != 0) {
return (void*) -1;
}
obj->counter++;
puts("supply");
pthread_cond_signal(&(obj->cond));
pthread_mutex_unlock(&(obj->mutex));
return NULL;
}
共有オブジェクトがリソース待ちをするプログラム。
つまりrun_waitはcounterが0になるまでへらし、run_notifyは
counterを1増やす。
注意点はwaitするとき、通知するときは同じmutexでロックすること。
mutexによる排他ロックを使った共有データの変更。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define THREAD_MAX (100)
typedef struct {
int var;
pthread_mutex_t mutex;
} SharedObject;
void* run(void* arg);
SharedObject* newSharedObject(void);
void destorySharedObject(SharedObject* obj);
int main(int argc, char* argv[])
{
SharedObject* obj;
pthread_t threads[THREAD_MAX];
int i;
obj = newSharedObject();
for (i = 0; i < THREAD_MAX; i++) {
pthread_create(&(threads[i]), NULL, &run, obj);
}
for (i = 0; i < THREAD_MAX; i++) {
int ret;
pthread_join(threads[i], (void**) &ret);
printf("result %dth: id=%d result=%d\n", i, (int) threads[i], ret);
}
destorySharedObject(obj);
puts("main exit");
return 0;
}
SharedObject* newSharedObject(void)
{
SharedObject* obj;
obj = malloc(sizeof(SharedObject));
obj->var = 0;
pthread_mutex_init(&(obj->mutex), NULL);
return obj;
}
void destorySharedObject(SharedObject* obj)
{
pthread_mutex_destroy(&(obj->mutex));
free(obj);
}
void* run(void* arg)
{
SharedObject* obj = arg;
int val;
int ret;
ret = pthread_mutex_lock(&(obj->mutex));
if (ret != 0) {
return (void*) -1;
}
obj->var++;
val = obj->var;
printf("thread %d: val=%d\n", (int) pthread_self(), obj->var);
ret = pthread_mutex_unlock(&(obj->mutex));
if (ret != 0) {
return (void*) -1;
}
return (void*) val;
}
排他する単位ごとにmutexを使う。 排他する領域はなるべくちいさくするのがいい。
データ渡しっぱなしでスレッド立ち上げ。 gccのオプションでは-lpthreadが必要。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define THREAD_MAX (100)
typedef struct {
int var;
} DetachObject;
void* run(void* arg);
DetachObject* newDetachObject(int i);
void destoryDetachObject(DetachObject* obj);
int main(int argc, char* argv[])
{
int i;
for (i = 0; i < THREAD_MAX; i++) {
pthread_t thread;
pthread_attr_t attr;
DetachObject* obj;
obj = newDetachObject(i);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&thread, &attr, &run, obj);
}
puts("main exit");
return 0;
}
DetachObject* newDetachObject(int i)
{
DetachObject* obj;
obj = malloc(sizeof(DetachObject));
obj->var = i;
return obj;
}
void destoryDetachObject(DetachObject* obj)
{
free(obj);
}
void* run(void* arg)
{
DetachObject* obj = arg;
printf("thread %d: count=%d\n", (int) pthread_self(), obj->var);
destoryDetachObject(obj);
return NULL;
}
「スレッドに渡すオブジェクト」と「スレッドで実行する関数」を定義 するというのが基本。DETACHはjoinしない(戻り値を使わない)スレッドに使う。
サーバ
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "define.h"
void process_connection(int cfd, int counter) ;
int server_open(int port, int backlog);
int main(int argc, char* argv[]) {
int sfd;
int connect_count = 3;
int i;
sfd = server_open(PORT, connect_count);
if (sfd < 0) {
perror("server");
exit(1);
}
for (i = 0; i < connect_count; i++) {
int cfd;
struct sockaddr_in caddr;
int len;
len = sizeof(caddr);
cfd = accept(sfd, (struct sockaddr*) &caddr, &len);
if (cfd < 0) {
perror("client");
continue;
}
process_connection(cfd, i);
shutdown(cfd, SHUT_RDWR);
close(cfd);
}
close(sfd);
return 0;
}
void process_connection(int cfd, int counter)
{
char buf[BUFSIZE];
int ret;
ret = read(cfd, buf, BUFSIZE);
buf[0] = '0' + counter;
puts(buf);
write(cfd, buf, BUFSIZE);
}
int server_open(int port, int backlog)
{
int sfd;
int optval;
struct sockaddr_in saddr;
int ret;
sfd = socket(PF_INET, SOCK_STREAM, 0);
if (sfd < 0) {
return sfd;
}
optval = 1;
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
memset((char*) &saddr, 0, sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = INADDR_ANY;
ret = bind(sfd, (struct sockaddr*) &saddr, sizeof(saddr));
if (ret < 0) {
close(sfd);
return ret;
}
ret = listen(sfd, backlog);
if (ret < 0) {
close(sfd);
return ret;
}
return sfd;
}
listenのbacklogは待ち受けする数。setsockoptのSO_REUSEADDRを1にすることは
連続してこのプログラムを実行するのに必要な処理です。shutdownはストリームを
閉じるものです(man 2 shutdown)。
クライアント
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include "define.h"
int connect_server(char* host, int port) ;
void process_connection(int cfd);
int main(int argc, char* argv[]) {
int cfd;
cfd = connect_server(HOST, PORT);
if (cfd < 0) {
perror("connect");
exit(1);
}
process_connection(cfd);
shutdown(cfd, SHUT_RDWR);
close(cfd);
return 0;
}
void process_connection(int cfd)
{
char buf[BUFSIZE];
strcpy(buf, "X is counter");
write(cfd, buf, BUFSIZE);
read(cfd, buf, BUFSIZE);
puts(buf);
}
int connect_server(char* host, int port)
{
int cfd;
struct sockaddr_in caddr;
struct hostent* hp;
int ret;
cfd = socket(PF_INET, SOCK_STREAM, 0);
if (cfd < 0) {
return -1;
}
memset((char*) &caddr, 0, sizeof(struct sockaddr_in));
caddr.sin_family = AF_INET;
caddr.sin_port = htons(port);
hp = gethostbyname(host);
memcpy(&caddr.sin_addr.s_addr, *hp->h_addr_list, hp->h_length);
ret = connect(cfd, (struct sockaddr*) &caddr, sizeof(caddr));
if (ret < 0) {
close(cfd);
return ret;
}
return cfd;
}
クライアントはbindではなくconnectを使って接続します。
bindが自分のアドレスを指定するのに対し、connectは相手のアドレスを指定します。
共通ヘッダ
#define PORT 9977 #define HOST "localhost" #define BUFSIZE 1024
PORTやHOSTは引数で設定することができるようにするべきだろう。