0

私のプロジェクトの3つの異なるモジュールで使用される単純なサーバーを実装したいと思います。
これらのモジュールはサーバーにデータを送信し、サーバーにファイルを保存し、これらのモジュールがジョブを完了するとこれらの情報をマージします。 これらの情報はすべて、タイムスタンプ(浮動小数点数)とラベル(浮動小数点数または文字列)を持ちます。Rustマルチスレッドサーバーで使用できる構造を作成するにはどうすればよいですか?

これは、これらの情報を保存するために私のデータ構造である:

pub struct Data { 
    file_name: String, 
    logs: Vec<(f32, String)>, 
    measures: Vec<(f32, f32)>, 
    statements: Vec<(f32, String)>, 
} 

は、私は、サーバーと対話するsocketを使用しています。

も使用してData構造体を実装し、これらのモジュールごとに共有可能にします。
したがって、私はクライアントを処理するとき、モジュールによって送信されたメッセージが正しいかどうかを確認し、それが良いデータ構造フィールド(logsmeasuresまたはstatements)にメッセージを処理して保存する新しい関数を呼び出すかどうかを確認します。 。

// Current ip address 
let ip_addr: &str = &format!("{}:{}", 
          &ip, 
          port); 

// Bind the current IP address 
let listener = match TcpListener::bind(ip_addr) { 
    Ok(listener) => listener, 
    Err(error) => panic!("Canno't bind {}, due to error {}", 
         ip_addr, 
         error), 
}; 

let global_data_struct = Data::new(DEFAULT_FILE.to_string()); 
let global_data_struct_shared = Arc::new(global_data_struct); 

// Get and process streams 
for stream in listener.incoming() { 
    let mut global_data_struct_shared_clone = global_data_struct_shared.clone(); 
    thread::spawn(move || { 
     // Borrow stream 
     let stream = stream; 
     match stream { 
      // Get the stream value 
      Ok(mut stream_v) => { 
       let current_ip = stream_v.peer_addr().unwrap().ip(); 
       let current_port = stream_v.peer_addr().unwrap().port(); 
       println!("Connected with peer {}:{}", current_ip, current_port); 
       // PROBLEM IN handle_client! 
       // A get_mut from global_data_struct_shared_clone 
       // returns to me None, not a value - so I 
       // can't access to global_data_struct_shared_clone 
       // fields :'(
       handle_client(&mut stream_v, &mut global_data_struct_shared_clone); 
      }, 
      Err(_) => error!("Canno't decode stream"), 
     } 
    }); 
} 

// Stop listening 
drop(listener); 

私にArc::get_mut(global_data_struct_shared_clone)戻りNoneので、私は、global_data_struct_shared_cloneのフィールドを処理するhandle_clientで変更可能な参照を取得するためにいくつかの問題を持っている - により、各着信要求に対してglobal_data_struct_shared.clone()へ。

これらの3つのモジュール間でこの構造を正しく管理するのに助けてくれる人がいますか?

+0

'Arc >'を使ってみましたか? –

+0

いいえ、特に私のモジュールの誰もモジュールによって既に存在するフィールドにアクセスすることはないので、私は 'Mutex'を使って問題が発生すると思います。各モジュールは 'Data'に独自のフィールドを持っています - したがって、' Arc 'に 'Mutex'を与えると無駄に私の構造体をブロックするでしょう...? – WebTogz

+0

これは処理中にブロックするだけですが、より細分化して完全に行うことができます:) –

答えて

0

錆の洞察は、強制的にメモリの安全性を達成することです。エイリアシングXORの変異性。この単一の原理を強制

は、バグのクラス全体を防ぐ:ポインタ/(目標でした)イテレータの無効化ともデータ競合を。


できるだけ、Rustはこの原則をコンパイル時に強制しようとします。ただし、ユーザーが専用の型/メソッドを使用してオプトインする場合は、実行時にもその機能を実行できます。

Arc::get_mutである。 Arc(Atomic Reference Countedポインタ)は、複数の所有者間の参照を共有するためのもので、エイリアスを意味し、その結果デフォルトでは変更が許可されません。 Arc::get_mutはランタイムチェックを実行します。ポインタが実際にエイリアス(1のカウント)でない場合、それは変更可能です。

しかし、実現したように、その時点でArcにエイリアスが設定されているため、これは適切ではありません。


他のタイプに切り替える必要があります。

最も簡単な解決策はArc<Mutex<...>>で、Arcは一緒にあなたがMutexによって強制実行時制御可変性と共有することができ、Mutexが制御可変性を可能にする、共有することができます。

これは粗いですが、十分に十分かもしれません。

もっと洗練されたアプローチでは、RwLock(リーダー/ライターロック)、より細かいMutexまたはアトミックを使用できます。私は単一のMutexで始まることをお勧めし、それがどのように行くかを見て、あなたが実行する前に歩く必要があります。

関連する問題