2017-03-01 13 views
3

私はループで動作しているワーカースレッドを持っています。私はマネージャスレッドを持っています。keeps a watchful eye on whether the first thread has done any work recentlyスレッドからタイムスタンプを共有する

これを行う最も簡単な方法は、タイムスタンプを含む変数を持つことです。ワーカースレッドが何らかの作業をしたときに変数に現在時刻を書き込み、マネージャースレッドが作業者をチェックしたいときは変数から時刻を読み取り、現在時刻との差を測定します。

まず、この変数はアトミックである必要がありますか?私の本能は、スレッド間で通信する際にアトミックを使用することですが、この場合、リード・モディファイ・ライト・サイクルはなく、1つのスレッドだけがアップデートを行っています。時間の値は1つの単語に収まるほど小さくなければならないので、恐らく単語の引き裂きに対する心配はありません。何らかの理由でスレッド間のタイムリーな伝播を促進するためには依然として原子的でなければならないのでしょうか?そうでない場合、タイムスタンプを共有する正しい方法は何ですか?

第2に、タイムスタンプを表すのに適したタイプは何ですか?また、そのインスタンスを取得するにはどうすればよいですか。 std :: time :: Instantは明らかな選択肢のように思えますが、それは同期または送信ではなく、どうやって原子1を持つのか分かりません。より良い選択肢がありますか?

+1

場合、それは絶対に原子あるいは同期させる必要があります。タイムスタンプは必ずしも必要ではありません。あなたが知りたいのは、前回チェックしたときからスレッドが何かをしているかどうかだけであれば、単純なアトミックフラグができます。 –

答えて

1

std::time::Instant actually does implement Send。ドキュメントにSendまたはSyncを実装するすべてのタイプが表示されるわけではありません。負の実装(例:Rc)と明示的な実装(例:Arc)のみが表示されます。 SendSyncは、すべてのフィールドが特性を実装している場合(つまり、すべてのフィールドがSendで、タイプがSendの場合、コンパイラがカスタムタイプ用に実装する言語機能(Rust 1.15.1ではまだ不安定です) Sync)。明示的な実装(形はunsafeと定義されているのでunsafeとマークする必要があります)は、ネガティブな実装をオーバーライドするために存在します(ルートは未加工のポインタ型であり、他のネガティブ実装は完全に余分ですが、 。もちろん、型にプライベートフィールドがある場合、その型がSendおよび/またはSyncを実装する場合は、ドキュメントを調べるだけではわかりません。チェックする最善の方法は、それを必要とする少しのコードをコンパイルしようとすることです。

したがって、共有可能な変更可能なInstantが必要な場合は、Arc<Mutex<Instant>>!を使用してください。

+0

これはSyncとSendに関する大きな啓示です!生成されたドキュメントには含まれていないのは本当に残念ですが、私はコンパイルトリックを使ってそれを使って暮らすことができます。 –

+0

可能であれば、私はミューテックスを避けたいと思います。マネージャスレッドには手間がかかりますが、ワーカースレッドはすべてのサイクルがカウントされる可能性のある作業を行っていますので、データを共有するための最速の方法をご希望します。 –

2

私がこれまで行ってきたことは、自分のAtomicInstantを書くことです。インスタントのコンテンツはプラットフォーム固有のものであり、隠れていますが、Durationの形式で別のインスタントからオフセットに変換することができます。これは、次にナノ秒カウントに変換されます。それは順番に、あなたのマシンのワードサイズ(1日約2 ** 46ナノ秒で、あなたが測定している時間があまりにも大きくならない限り動作するusizeに詰め込むことができます、64ビットマシンは約350年を測定することができます)。その連鎖はすべて値を読み取るために逆にすることができます。

コードは(わずかに編集したので、これは間違っている可能です)、このようになります:1つのスレッドが書いている

struct AtomicInstant { 
    base: Instant, 
    offset: AtomicUsize, 
} 

impl AtomicInstant { 
    fn new(base: Instant) -> AtomicInstant { 
     AtomicInstant { 
      base: base, 
      offset: AtomicUsize::new(0), 
     } 
    } 

    fn load(&self, order: Ordering) -> Instant { 
     let offset_nanos = self.offset.load(order) as u64; 
     let secs = offset_nanos/1_000_000_000; 
     let subsec_nanos = (offset_nanos % 1_000_000_000) as u32; 
     let offset = Duration::new(secs, subsec_nanos); 
     return self.base + offset; 
    } 

    fn store(&self, val: Instant, order: Ordering) { 
     let offset = val - self.base; 
     let offset_nanos = offset.as_secs() * 1_000_000_000 + offset.subsec_nanos() as u64; 
     self.offset.store(offset_nanos as usize, order); 
    } 
} 
関連する問題