2020年5月23日 (土)

生産者・消費者問題 -2-

生産者・消費者問題 では資源へアクセスするタイミングに制限が有りましたが、今回は、その制限を外して考えることにします(もちろん、不整合が生じないという制限は付きます)。とにかく、生産者は、バッファに空きが有れば随時、データを置き、消費者はバッファにデータが有れば随時、持って行くということをコーディングします。

問題を整理すると下記のようになります。

  • 生産者は1人、消費者は複数人。
  • データを置く領域は n_buf 個のバッファで構成されている。
  • アクセスできるタイミングでアクセスする(全バッファが埋まったり、全て空にならなくてもアクセスする)。

生産者は下記 producer() のようになります。

void producer(void)
{
    while (1){
        ・・・
        n_data = make_data();
        sem_wait(&room, my_id);    // (1-1)
        do {
            int n = put_buf();     // (1-2)
            sem_sig(&stock);       // (1-3)
        } while ((n < n_buf)&&(--n_data));  // (1-4)
        ・・・
    }
}

room はバッファの空きを示す2進セマフォ(注意1)です。そのセマフォを使って、バッファに空きが出来るのを待ち(1-1)、空きが出来ればバッファにデータを置きます(1-2)。その時、埋まっているバッファの数を返してもらいます。データを1つ置く毎に計数セマフォ stock のシグナルを送ります(1-3)。このセマフォの値はデータが置かれているバッファ数を示しています。バッファに空きが有り、且つ、用意したデータを置き切れていないうちは (1-2), (1-3) を繰り返します(1-4)。

(注意1):2進セマフォでは、セマフォ値が 1 の時は sem_sig() しても何も変わらないという認識でいますが、それでOK?

消費者は下記 consumer() のようになります。

void consumer(void)
{
    while (1){
        int ticket;
        sem_wait(&stock, my_id);    // (2-1)
        sem_wait(&queue, my_id);    // (2-2)
        ticket = get_ticket();      // (2-3)
        sem_sig(&queue);        // (2-4)
        take_buf(ticket);       // (2-5)
        sem_sig(&room);
        ・・・
    }
}

バッファにデータが置かれるのを計数セマフォ stock で待ちます(2-1)。このセマフォの初期値はバッファ数 n_buf です。データへのアクセスは複数の消費者が試みている可能性が有るので、 (2-1) を通過しただけではバッファにアクセスしてはいけません。アクセスの衝突を防ぐために、バッファの選択(2-3)を排他的に行います。その排他的選択のために2進セマフォ queue を待ちます(2-2)。 ticket が選択したバッファ(の番号)を表します。バッファを選択したらすぐにセマフォ queue のシグナルを送り、他の消費者がバッファの選択を出来るようにします(2-4)。これでバッファからデータを取り出すことが出来ます(2-5)。取り出した後は、バッファに空きが出来たことを知らせるためにセマフォ room のシグナルを送ります。

バッファの選択を排他的に実行するために、セマフォ queue を使用していますが、これは要件の割にはコストが高いので、もっと安価なスピンロックの方が良いと思います(注意2)。ここでは簡単のためセマフォのみの例を示しました。

(注意2): (2-2) ~ (2-4) は短時間で処理出来るという前提です。

今回はセマフォとして下記の3つのセマフォを使いましたが、 room, stock の2つと queue は違った意味を持っています。 roomstock はバッファへのアクセスに際して、生産者と消費者の間で同期を取るためのものであるのに対して、 queue はバッファを選択する際の消費者同士の相互排除を目的としています。ひと口にセマフォと言っても、それには2通りの目的(働き)が有りますが、今回のコードは両方の目的(働き)を示せる興味深い例になっています。

    セマフォの働き
  • room :同期
  • stock:同期
  • queue:排除

2020年5月19日 (火)

古傷のデバッグ(<span class="sl_ft" style="font-weight:normal">FlatTable</span>)

FlatTable (ビリヤード配置図ソフト)のバグを修正しました。このバグは PC では発生せず、スマートフォンで発生していました。その症状と対処を以下に示します。

症状

配置図

FlatTable の両側に▲が4個ずつ並んでいますが、これらは球を移動させるボタンです。このボタンは次のように操作することになっていました。

  • PC:移動ボタンの上でマウスボタンを押し続けると、その間、球が移動する。
  • スマフォ:移動ボタンをタップすると球が移動を開始し、再度タップすると停止する。

ところが、スマートフォンでは次のような症状が確認されました。

    エラーの症状
  1. タップの場合:球は少しだけ移動して止まる(移動し続けない)。
  2. 数秒間押し続けてから離した場合:球が移動し続けて、指を離しても球は止まらない。

このボタンを押す(タップもしくは押し続ける)と下記コードを実行するようになっていました。今はスマートフォンを問題にしているので (1) は真です。

var btnDeltX;
var btnDeltY;
var tpStop = true;
var tpId;

function moveByBtn(evt, deltX, deltY){
    ・・・
    move(curObj, deltX, deltY);

    btnDeltX = deltX;
    btnDeltY = deltY;
    if (fTouchPnl){            // (1)
        if (tpStop = !tpStop){    // (2)
            clearInterval(tpId);  // (3)
        } else {
            tpId = setInterval("willGo()", 300);  // (4)
        }
    } else {
        var id = setInterval("willGo()", 200);
        target.onmouseup = function (){
            clearInterval(id);
            target.onmouseup = null;
        };
    }
}

実は、上記コードになった経緯がタッチパネルはよく解らん -5-に有ります。8年前にも、この箇所で苦労したことが書かれています。その時は問題を解消したつもりでいたのですが・・・。

タップの場合、コードの (2) はまず tpStop = false になるので、 (4) が実行されます。 willGo() は球を少し移動するルーチンです。この (4) により球は移動し続けます。2回目のタップで (2) は tpStop = true となり、 (3) が実行されて球は止まるはずです。実際は、1回目のタップですぐに止まるので不思議です。また、押し続けてもタップと同じ動きをするはずなのに、実際は球が移動し続けるのも不思議です。

対処

とにかく、アレコレ試行錯誤して最終的に下記コードになりました。上記のダメだったコードでは PC とスマートフォンを別扱いしていましたが、下記コードでは共通のコードにまとめています。また、ボタンの操作方法も PC と同じにしました。

var btnDeltX;
var btnDeltY;

function dmyHdl(evt){
    evt.preventDefault();    // (5)
}

function moveByBtn(evt, deltX, deltY){
    ・・・
    move(curObj, deltX, deltY);

    btnDeltX = deltX;
    btnDeltY = deltY;
    var id = setInterval("willGo()", 200);  // (6)
    target[onMouseUp] = function (){        // (7)
        clearInterval(id);
        target[onMouseUp] = dmyHdl;
        refresh();    // (8)
    }
}

まず、注意を1つ。 (7) の onMouseUp は PC では onMouseUp = "onmouseup", スマートフォンでは onMouseUp = "ontouchend" になっています。このように、 onMouseUp は文字列なので、これを用いてプロパティを指定しようと target.onMouseUp としてもダメでした。 (7) のように [ ] を使用する必要が有るようです。

では、上記コードの動作を説明します。 (6) で球は 200 msec 毎に少しずつ移動させていることが分かります。その後、 (7) で onMouseUp を検出して function を実行します。 (8) の refresh() は仮想マウスパッドを再表示するルーチンです。 LongDriver (フットボールのプレイブック・ソフト)のデバッグをした時の touchEvent の奇妙な振る舞いを回避するための処理を、ここでも使いました。もし、この refresh() が無いと、見た目には判らないエラーが発生します。

もし、ボタン操作がタップだった場合は、ここに示したルーチン moveByBtn() を実行する前にイベント touchend が発生するかも知れません。それで、前もって touchend のイベントハンドラーとして (5) の dmyHdl() を登録しておき、そのハンドラーで必要な処理をします。その処理とは・・・ evt.preventDefault() のみ。初めは、このハンドラーでフラッグ処理( touchend の有無を設定)を試したのですが、それは不必要という結論になりました。一方、 eve.preventDefault() をコメントアウトすると正常な動作になりません。 eve.preventDefault() だけのイベントハンドラーが役に立つとはビックリです。これ、業界の常識でしょうか?

今回、ブレイク・ポイントを設定すると動作が変わるという事態が有り、問題点を正しく把握するのに苦労しました。微妙なタイミングが問題となるようなコードは、どうやってデバッグすれば良いのでしょうか?

2020年5月 2日 (土)

共振器QED

ドレスト光子の本を読んでいると引っ掛かる所が幾つも有りますが、その1つが、

  • ドレスト光子は、考えている領域がその波長より小さいため、共振器を想定出来ない。

旨の記述です。私には、当初、その意味を汲み取ることが出来ませんでした。実は、共振器QED(量子電気力学)なるものが有ることを最近になって知りました。単純に解釈すると、共振器の内側でQEDを考えようというものです。その共振器QEDがドレスト光子以前に研究されていたので、それを踏まえて、ドレスト光子では「共振器が想定出来ない」という記述がなされたのだと思います。そこで、その共振器QEDについて、少し調べてみました。

まず、(光)共振器を一言で言うと、それは向かい合った1対の鏡のことです。その鏡に挟まれた空洞内で光は条件次第で定在波を形成して共振します。

向かい合った1対の鏡とその間の光

例として半導体1次元微小共振器を見てみると、その構造は、量子井戸(Quantum Well: QW)や量子ドットといった半導体発光層を持つ共振層を屈折率の異なる同種の半導体多層膜による DBR( Distributed Bragg Reflector:分布ブラッグ反射鏡)で挟んだものになっています。

共振器QEDは、そのような光共振器内で光と電子・正孔対(励起子)の相互作用を扱う学問(研究)分野です。共振器内では、光と励起子の相互作用を光子1個レベルで操ることが出来るようです。その光と励起子は強く相互作用することが出来、量子情報通信への応用が期待されるとのことです。そのような系を扱うのが共振器QEDと言うわけです。 YouTube に次の動画が有りました。

因みに、光と励起子が強く相互作用した状態が励起子ポラリトン(共振器ポラリトン)です。ドレスト光子と励起子ポラリトンは別物ですが、励起子ポラリトンや共振器QEDに関する知識が有れば、ドレスト光子の本を読んだ時に理解が捗っていたことでしょう。

ところで、物性に不勉強な私は、光が質量を持つことを知った時は驚いたものですが、物性界隈では光が質量を持つのは常識なのだろうなと思う今日この頃です。

2020年4月19日 (日)

横方向のはみ出し部分が切れることへの対応

当ブログでは数式を扱うことが多く有ります。それをスマートフォン(モバイル・モード)で見ると、次式のように数式が横方向へはみ出して切れる場合がほとんどです(PC モードだと切れない)。

\[ \mathscr{L} = -\frac{n_0e^2}{2mc^2}\boldsymbol{A}^2 + \frac{1}{8\pi}(\boldsymbol{E}^2 - \boldsymbol{B}^2) \tag{例} \]

今までは、スマートフォンで見ることが無かったので、それに気付かずにいました。しかし LongDriver のデバッグが切っ掛けで時々見るようになり、数式や図のはみ出しが気になって来ました。

そこで、はみ出した部分は横方向にスクロール出来るようにすることにしました。そのために、スタイルシートに (1) を定義して、

// (1)
.sl_math {
    overflow-x: auto;
}

記事中で横スクロールさせたい箇所を (2) のように挟みました。

<!-- (2) -->
<div class="sl_math">
    ・・・
</div>

ココログ(ベーシック)でスタイルシートの編集は、管理画面の「カスタム CSS を編集」で行います。

ところが、これらの作業を実施したにも関わらず、モバイル・モードで横スクロール出来るようにはなりませんでした。実は、ここで編集したのは PC モードのスタイルシートだったのです。では、モバイル・モードのスタイルシートを編集するのは、どうするか?・・・方法は有りません(たぶん)。結局、スタイルシートは使わずに記事中に直接 (3) を記入することにしました。

<!-- (3) -->
<div style="overflow-x: auto">
    ・・・
</div>

これで、スマートフォンでも数式などが切れることなく見れるようになりました。

\[ \mathscr{L} = -\frac{n_0e^2}{2mc^2}\boldsymbol{A}^2 + \frac{1}{8\pi}(\boldsymbol{E}^2 - \boldsymbol{B}^2) \tag{例} \]

それにしても、スタイルシートのカスタマイズが PC のみとはフザケタ仕様です。

2020年4月18日 (土)

またまたバグ発見 <span style="font-family:Impact;font-style:italic;font-weight:normal">LongDriver</span>

表題の通り、フットボールのプレイブック・ソフト LongDriver にバグが見つかりました。もちろん、スマートフォン限定のバグです。 LongDriver を単独で使用する時は良いのですが、 <iframe> 等で埋め込んだものは茶色のバーをタップしても、それが機能しません。例えば下記がそうです。

画像上下の選手ダミーマークをタップしたら、その選手が緑色になり、フィールドに薄暗いマスクが掛かります。その後、左右の茶色バーをタップすると、本来なら選手とフィールドの色が元に戻るのですが、上記画像は、そうなりません(←スマートフォンの場合)。下側の茶色バーに関しても機能しません。

なお、茶色バー上を指でなぞるとフィールドが上下左右にスライドする機能は働いています。ただし、動きがぎこちないですが。

今のところ、茶色バーをタップするような操作をしたい場合は、そのプレイブック・コードをコピーして、単独で表示させるしかテが有りません。プレイブック・コードは、画像右上の [Total][Gen. Full Code] で表示されるので、それをコピーします。コピーしたコードをアドレスバーに貼り付けると LongDriver が表示されます。

それにしても、スマートフォンのくそ仕様にはウンザリです。直った(治った)つもりが再発する・・・まるでCウィルス(注意)です。

(注意):Cウィルスの「C]はコロナとは違うっチャ。

追記:ブログの閲覧をスマートフォンで PC モードにすると、モバイル・モードとは違った結果になります。 PC モードでは、茶色バーのタップは機能します。その代り、茶色バーや仮想マウスパッド(フィールドの薄暗いマスク)上を指でなぞるドラッグは、画像自体がスライドしてドラッグになりません。ますます、混乱した状況になっています。

«鍵マーク?