質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.34%
Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

1回答

175閲覧

Rustでグローバルかつmutableなvectorの中身の部分一致を判定する処理が上手くいかない

DeepRoastBeans

総合スコア81

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

0クリップ

投稿2025/01/03 00:56

実現したいこと

サーバ側でPostされたデータを、Postされた都度、グローバルでmutableなvectorに値を入れていき、vectorに値が一定数貯まったら別の処理を行います。グローバルなvectorに値を入れる際に、既にvectorに入っている値と部分一致した場合は、vectorに値を入れないという処理を実装したいです。

発生している問題・分からないこと

once_cellを使用して以下のように実装したのですが、部分一致(ここでは、family, first, ageが一致)を判定するために、let mut binding = VECT.lock().unwrap(); とする(所有権の移転?)と、再度vectorに値を入れようと VECT.lock().unwrap().push(n4.clone()); としても、何も反応しません。
ターミナル上では、止まったままになります。
Finished dev profile [unoptimized + debuginfo] target(s) in 0.22s
Running target/debug/sample

binding.push(n4.clone());の場合は上手くいくのですが、それだと、グローバルなベクターに値が入りません。

グローバルでmutableなvector / once_cell 参考サイト
https://stackoverflow.com/questions/27791532/how-do-i-create-a-global-mutable-singleton

上手くいく実装の方法を教えていただきたいです。

エラーメッセージ

error

1Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s 2 Running `target/debug/sample` 3 4↑ ここから動かない

該当のソースコード

rust

1use once_cell::sync::Lazy; 2use std::sync::Mutex; 3use std::ops::DerefMut; 4use serde::{Serialize, Deserialize}; 5 6#[derive(Debug, Serialize, Clone, Deserialize)] 7struct Name { 8 family: String, 9 first: String, 10 age: u32, 11 note: String, 12} 13 14static VECT: Lazy<Mutex<Vec<Name>>> = Lazy::new(|| Mutex::new(vec![])); 15 16fn push_name() { 17 let n1 = Name {family: "yamada".to_string(), first: "taro".to_string(), age: 20, note: "AAA".to_string()}; 18 VECT.lock().unwrap().push(n1); 19 let n2 = Name {family: "tanaka".to_string(), first: "kazuo".to_string(), age: 18, note: "BBB".to_string()}; 20 VECT.lock().unwrap().push(n2); 21 let n3 = Name {family: "sato".to_string(), first: "hanako".to_string(), age: 22, note: "CCC".to_string()}; 22 VECT.lock().unwrap().push(n3); 23} 24 25fn main(){ 26 27 push_name(); 28 let n4 = Name {family: "yoshida".to_string(), first: "kyoko".to_string(), age: 15, note: "DDD".to_string()}; 29 30 let mut binding = VECT.lock().unwrap(); 31 let objs = binding.deref_mut(); 32 33 let mut flag = 0; 34 for v in objs { 35 if n4.family == v.family { 36 if n4.first == v.first { 37 if n4.age == v.age { 38 flag = 1; 39 } 40 } 41 } 42 } 43 if flag != 1 { 44 binding.push(n4.clone()); 45 } 46}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

VECTをそのままforループで回すなど色々数時間試したのですが、上手くいきませんでした。。

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

let mut binding = VECT.lock().unwrap(); とする(所有権の移転?)と、再度vectorに値を入れようと VECT.lock().unwrap().push(n4.clone()); としても、何も反応しません。
ターミナル上では、止まったままになります。

VECT.lock().unwrap().push(n4.clone())のところでデッドロックしているのが原因です。

std::sync::Mutexは、同じスレッド内で2回ロックしようとするとデッドロックします。2回目のロックを取得するには、1回目のロックを解放する必要があります。そうしないと、いつまで待っても2回目のロックが所得できないので、デッドロックします。

では、Mutexのロックがいつ解放されるのかというと、もし、ロックを保持している変数がある場合は、その変数がスコープを抜けたとき、または、drop関数(std::mem::drop)で明示的にロックをdropしたときになります。

以下のようにdrop関数を使って、1回目のロックを解放することでデッドロックを回避できます。

rust

1fn main(){ 2 3 push_name(); 4 let n4 = Name {family: "yoshida".to_string(), first: "kyoko".to_string(), age: 15, note: "DDD".to_string()}; 5 6 let mut binding = VECT.lock().unwrap(); 7 let objs = binding.deref_mut(); 8 9 let mut flag = 0; 10 for v in objs { 11 // 略 12 } 13 14 drop(binding); // 1回目のロックを解放する 15 16 if flag != 1 { 17 VECT.lock().unwrap().push(n4.clone()); 18 } 19 20 println!("{:?}", VECT.lock().unwrap()); 21}

binding.push(n4.clone());の場合は上手くいくのですが、それだと、グローバルなベクターに値が入りません。

こちらは再現できないようです。ご質問のコードではグローバルなベクターに値が入りました。(最後に drop(binding); println!("{:?}", VECT.lock().unwrap()); を追加して確認しました)

投稿2025/01/03 03:31

編集2025/01/03 03:38
tatsuya6502

総合スコア2055

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DeepRoastBeans

2025/01/03 03:42

おおお、素晴らしいですね!!!ちょっと感動しました。本当にありがとうございます!!!
tatsuya6502

2025/01/03 03:49

解決してよかったです!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.34%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問