アプリケーションが終了したら自動的に再起動させるAppleScript

タイトルのものを作ったので共有。動作としては5秒ごとにApplicationsディレクトリの"hoge.app"が起動していなかったら起動するというスクリプト。コードの該当箇所を変えれば秒数、起動アプリケーションが変えられる。
展示用のスクリプトで、異常終了した時も自動的に再起動させることで人手なしに展示自体を継続させるためのもの。スクリプト自体をScript Editorでアプリケーションとして書き出し、ログイン項目に追加することでMacの起動と同時にこのスクリプトが走るようにした。

on launchApp()
	if application "/Applications/hoge.app" is not running then
		tell application "/Applications/hoge.app"
			activate
		end tell
	end if
end launchApp

on run
	launchApp()
end run

on idle
	launchApp()
	return 5
end idle

追記(2016/08/08)

Twitterでこの記事を告知したところ、このようなリプライを頂いた。


対策の必要がある方はこちらの記事を参照することをおすすめする。

展示まわりに関する関連記事

qiita.com
miso-engine.hatenablog.com

openFrameworksでofThreadを利用しマルチスレッドを実装する

先日openFrameworks(以下oF)を使った仕事でどうしてもシングルスレッドだと画像の処理速度が遅いのでマルチスレッドにしたことがあった。Macを使っていたので、最初はiOSアプリを作っていた時代に使い慣れていたGCDを利用していたのだけど、どうもGCDを利用すると落ちたりはしないのだが、肝心の処理する画像が極稀にグリッチし、頻繁にメモリの位置が間違っていた。そこで、最終的にはC++のスレッドを扱う機能を抽象化したofThreadを利用してマルチスレッドの処理を実現したので、ofThreadの使い方のメモを残しておく。

oFにおけるマルチスレッドプログラミングの注意点

最初に注意点を書くと、oFの元となるOpenGLの限界によりOpenGL的な機能はマルチスレッド出来ない。というのもOpenGLはメインスレッド(GLスレッドと呼ばれる)で動く必要があるからだ。そのため、画像の処理においてはofImageなどは利用できないので、ofPixelsを利用する必要がある。

リソース

主に『ofBook』の"Threads"という記事で背景と利用方法を学んだ。またofxThreadedImageLoaderは最新版(ofv0.9.3)のoFに標準で添付されているAddonで、ofThreadを利用した分かりやすいサンプルになっており大変参考になった。

ofThreadの使い方

ofThreadを継承して使う。threadedFunction()というメソッドをオーバライドするのが必須である。これはofThreadのインスタンスをstartThreadした時に呼ばれるメソッドだ。そのスレッドのmain()みたいなものである。サンプルとして一番わかり易い『ofBook』の"Threads"チャプターの最初に載っているコードが分かりやすいので下記に転載する。

class ImageLoader: public ofThread{
    void setup(string imagePath){
        this->path = imagePath;
    }

    void threadedFunction(){
        ofLoadImage(image, path);
    }

    ofPixels image;
    string path;
}

//ofApp.h
bool loading;
ImageLoader imgLoader;
ofImage img;

// ofApp.cpp
void ofApp::setup(){
    loading = false;
}

void ofApp::update(){
    if(loading==true && !imgLoader.isThreadRunning()){
        img.getPixelsRef() = imgLoader.image;
        img.update();
        loading = false;
    }
}

void ofApp::draw(){
    if (img.isAllocated()) {
        img.draw(0, 0);
    }
}

void ofApp::keyPressed(int key){
    if(!loading){
        imgLoader.setup("someimage.png");
        loading = true;
        imgLoader.startThread();
    }
}

このコードはImageLoaderのスレッドでofPixelsで画像を読み込み、メインスレッドでその状態を監視しofPixelsに読み込み終わったらofImageにofPixelsのポインタを渡してやることでofImage側での描画を可能にする、という仕組みである。

ofMutex

さて上記コードは恐らくそのまま動く*1排他制御をしていない。複数のスレッドが同時にメモリの同じ場所にアクセスし読み書きするとクラッシュするため、マルチスレッドプログラミングにおいてはメモリの同じ場所には1つのスレッドからしかアクセスできないようにしてやる必要がある。これはプログラマ側の責任だ。
排他制御のためにmutexが存在する。あるスレッドからmutexをlockをすると、他のスレッドはそのmutexがunlockされるまでlockすることができなくなるという仕組みである。後からlockしようとした他のスレッドはそのmutexがunlockされるまで動作が止まった状態になるため、lockしたならばなるべくはやくunlockする必要がある。
ofMutexの具体的な使い方だが、『ofBook』の"Threads"チャプターに適切な例があるので再び引用する。

class NumberGenerator{
public:
    void threadedFunction(){
        while (isThreadRunning()){
            lock();
            numbers.push_back(ofRandom(0,1000));
            unlock();
            ofSleepMillis(1000);
        }
    }

    vector<int> numbers;
}

// ofApp.h

NumberGenerator numberGenerator;

// ofApp.cpp

void ofApp::setup(){
    numberGenerator.startThread();
}

void ofApp::update(){
    numberGenerator.lock();
    while(!numberGenerator.numbers.empty()){
        cout << numberGenerator.numbers.front() << endl;
        numberGenerator.numbers.pop_front();
    }
    numberGenerator.unlock();
}

まとめと余談

ほぼ『ofBook』の抄訳みたいになってしまったので、詳しくはそちらを参照してほしい。
今から考えるとCPUに計算させるから遅いのであって、GPU、つまりShaderで処理してしまえばよかったのでは?という感じもあるが、実際の画像処理部分は自分が実装するのではなく、他者からの提供であり実装を変えてしまうと結果が変わる可能性があったので、最もマシな解決策だったと思われる。なおShaderはこの記事の元となる仕事とは別案件で利用したので、そのうち書くかもしれない。

*1:確認はしていない

USBポートの少ないラップトップにピッタリのUSBハブ

MacbookシリーズはProにしろAirにしろUSBポートが2つしかない。ポートが足りなくなったと時は、特に深く考えずにその辺にあるUSBハブを使ってきたのだが、最近買ったエレコムUSB2.0用ハブが良くてTwitterで紹介した。この記事はそのまとめ。

商品

このハブ、ひとつのUSBポートが3つに増える、という形になっている。ポートの部分が回転するおかげでラップトップにピッタリ沿うし、シチュエーションによって倒したい、立てたい、みたいなのに対応出来るのも良い。

ツイート


まとめ

Arduino3つ繋げた状態で8時間シリアル通信してても問題なかったので良かった。ケーブルが生えてるタイプだとゴチャゴチャするので、単純にバスパワーで動くものを増やしたいという時に便利だと思う。