2

一般に、あるクラスを継承するクラスがあり、そのクラスのインスタンスが実行終了後に自動的に割り当てを解除Threadされるようにしたい場合、delete this

具体例:

私のアプリケーションには、 という1 つのメソッドを持つTimerクラスがあります。ユーザーは次のように呼び出します。staticschedule

Timer::schedule((void*)obj, &callbackFunction, 15); // call callbackFunction(obj) in 15 seconds

このscheduleメソッドはTaskオブジェクトを作成します (目的は Java TimerTask オブジェクトに似ています)。Taskクラスはクラスに対するprivateものであり、Timerクラスから継承しますThread(pthreads で実装されます)。したがって、scheduleメソッドはこれを行います:

Task *task = new Task(obj, callback, seconds);
task->start(); // fork a thread, and call the task's run method

コンストラクターはTask、新しいスレッドで使用するために引数を保存します。新しいスレッドでは、タスクのrunメソッドが次のように呼び出されます。

void Timer::Task::run() {
    Thread::sleep(this->seconds);
    this->callback(this->obj);
    delete this;
}

task新しいスレッドが必要とするため、オブジェクトをスタック割り当てオブジェクトにすることはできないことに注意してください。また、他の人が使用できないようにTaskクラスprivateTimerクラスにしました。

Taskオブジェクトを削除するということは、基になるオブジェクトを削除することを意味するため、特に心配していThreadます。Threadオブジェクトの唯一の状態はpthread_t変数です。これが戻ってきて私を噛む方法はありますか?メソッドが終了pthread_tした後は変数を使用しないことに注意してください。run

(メソッドへの引数またはコンストラクター内の何かdelete thisを介して) ある種の状態を導入することにより、呼び出しをバイパスすることができます。これは、メソッドを呼び出しているオブジェクトに対してフォークされるメソッドであることを示します。ただし、コードはそのまま動作するようです。Thread::startThreaddeleterun

何かご意見は?

4

4 に答える 4

3

run() メソッドで後で何もしない限り、「これを削除」は安全だと思います (タスクのオブジェクトのメンバー変数などはすべて、その時点でメモリが解放されるため)。

私はあなたのデザインについて疑問に思っています...誰かがタイマーコールバックをスケジュールするたびに、本当に新しいスレッドを生成したいですか? それは私にはかなり非効率に思えます。少なくとも後で最適化するために、スレッド プール (または、実際にはサイズ 1 のスレッド プールである単一の永続的なタイマー スレッド) の使用を検討することができます。(または、さらに良いことに、余分なスレッドをまったく生成せずにタイマー機能を実装します...タイムアウト機能(select()またはWaitForMultipleObjects()など)を備えたイベントループを使用している場合、任意の数の独立したオブジェクトを多重化できます単一スレッドのイベントループ内のタイマーイベント)

于 2010-02-09T06:28:37.167 に答える
2

delete this;次のことを保証する限り、特に恐ろしいことは何もありません。

  1. オブジェクトは常に動的に割り当てられます。
  2. 削除された後は、オブジェクトのメンバーは使用されません。

これらの最初のものは難しいものです。役立つ手順 (ctor を非公開にするなど) はありますが、誰かが一生懸命やろうとすれば、ほとんどすべてのことを回避できます。

そうは言っても、おそらくある種のスレッドプールを使用したほうがよいでしょう。より効率的でスケーラブルになる傾向があります。

編集:バイパスについて話したとき、次のようなコードを考えていました:

class HeapOnly {
  private:
    HeapOnly () {} // Private Constructor.
    ~HeapOnly () {} // A Private, non-virtual destructor.
  public:
    static HeapOnly * instance () { return new HeapOnly(); }
    void destroy () { delete this; }  // Reclaim memory.
};

これは私たちが提供できる保護とほぼ同じですが、それを回避するのは簡単です:

int main() { 
    char buffer[sizeof(HeapOnly)];

    HeapOnly *h = reinterpret_cast<HeapOnly *>(buffer);
    h->destroy(); // undefined behavior...
    return 0;
}

このように直接だと、この状況はかなり明白です。オブジェクトファクトリが実際にオブジェクトを生成し、別の場所のコードが完全にメモリを割り当てているなど、大規模なシステムに分散している場合、追跡がはるかに困難になる可能性があります。

私は最初に「特に恐ろしいことは何もない」delete this;と言ったが、私はそれを支持する. 他のコードが「他のコードとうまく動作しない」場合に発生する可能性のある問題の種類について警告しようとしています。

于 2010-02-09T06:32:13.950 に答える
1

delete thisスレッドが使用するために明示的に割り当てたメモリを解放しますが、スレッドのコール スタックやカーネル スレッド/プロセス構造 (該当する場合) など、OS または pthreads ライブラリによって割り当てられたリソースはどうでしょうか? 呼び出しpthread_join()たり、 detachstatepthread_detach()を設定したりしない場合は、まだメモリ リークが発生していると思います。

Threadまた、クラスがどのように使用されるように設計されているかによっても異なります。pthread_join()デストラクタを呼び出す場合、それは問題です。

pthread_detach()(オブジェクトが既に実行している可能性がある)を使用し、 を削除した後Threadに逆参照しないように注意している場合、このアプローチは実行可能であると思いますが、寿命の長いスレッド (またはスレッド プール) を使用するという他の提案は適切です。検討する価値があります。thisthis

于 2010-02-09T16:01:14.437 に答える
1

Taskオブジェクトを使ってnewそれを、startそれを、そしてそれを処理deleteするだけなら、そもそもなぜオブジェクトが必要になるのでしょうか? start(オブジェクトの作成と削除を除いた) 何をする関数を単純に実装しないのですか?

于 2010-02-09T06:54:17.830 に答える