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

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

新規登録して質問してみよう
ただいま回答率
85.35%
プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

2714閲覧

マルチスレッドの実装(C++)

00_x9925

総合スコア12

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/06/11 16:02

[C++]以下の問題をマルチスレッドで解くために,コードを書いてみましたがうまくいきません. エラーは出ませんが,肝心の出力変数sum_sakuraとsum_tomoyoが0のままファイルに書き込まれます.
マルチスレッドはどのように実装すればよいのでしょうか?

sakuraさんとtomoyoさんの初期位置は自宅で、店にはリンゴが100個あります.
リンゴが完売した時点でプログラムは終了です.
最終的にsakuraさんとtomoyoさんはそれぞれ何個のリンゴを購入しましたか?

sakuraさん
・家からの店への片道時間(帰りも同じ) 1秒
・自宅での荷降ろし 3秒
・八百屋での店員とのやり取り 1秒
・一度に購入できるりんごの個数 5個
tomoyoさん
・家からの店への片道時間(帰りも同じ) 2秒
・自宅での荷降ろし 1秒
・八百屋での店員とのやり取り 2秒
・一度に購入できるりんごの個数 3個
店員akira
・客は1人ずつしか対応できない
・店にはりんごが100個ある

C++

1#include "C2_report10.h" 2 3int main() 4{ 5 // カレントディレクトリの取得 6 char s_currentDir[_MAX_PATH]; 7 GetCurrentDirectory(sizeof(s_currentDir), s_currentDir); 8 // ファイルパスの作成(iniファイルから読み込み) 9 char s_inifile[_MAX_PATH]; 10 sprintf_s(s_inifile, "%s\C2_report10.ini", s_currentDir); 11 12 //構造体にiniファイルのデータを格納 13 //sakura 14 struct Customer sakura, tomoyo; 15 sakura.travel_time = GetPrivateProfileInt("sakura","travel_time", -1, s_inifile); 16 sakura.home_time = GetPrivateProfileInt("sakura", "home_time", -1, s_inifile); 17 sakura.exchange_time = GetPrivateProfileInt("sakura", "exchange_time", -1, s_inifile); 18 sakura.having_apple = GetPrivateProfileInt("sakura", "having_apple", -1, s_inifile); 19 //tomoyo 20 tomoyo.travel_time = GetPrivateProfileInt("tomoyo", "travel_time", -1, s_inifile); 21 tomoyo.home_time = GetPrivateProfileInt("tomoyo", "home_time", -1, s_inifile); 22 tomoyo.exchange_time = GetPrivateProfileInt("tomoyo", "exchange_time", -1, s_inifile); 23 tomoyo.having_apple = GetPrivateProfileInt("tomoyo", "having_apple", -1, s_inifile); 24 //akira 25 struct Shop akito; 26 akito.all_apple = GetPrivateProfileInt("akito", "all_apple", -1, s_inifile); 27 28 //sakuraとtomoyoのそれぞれのりんご所持限界 29 sakura_max = 5; 30 tomoyo_max = 3; 31 32 //sakuraとtomoyoの接客時間設定 33 sakura_exchanging = sakura.exchange_time; 34 tomoyo_exchanging = tomoyo.exchange_time; 35 36 //turn_time設定 37 sakura_turn_time = sakura.travel_time * 2 + sakura.home_time; 38 tomoyo_turn_time = tomoyo.travel_time * 2 + tomoyo.home_time; 39 40 //マルチスレッドスタート↓ 41 //next_time変数を自宅から店までの片道時間に初期化 42 float sakura_next_time = sakura.travel_time; //sakuraが次にりんごを買いに来るまでの時間 43 float tomoyo_next_time = tomoyo.travel_time; //tomoyoが次にりんごを買いに来るまでの時間 44 45 std::thread th1(ThreadProcess1); 46 std::thread th2(ThreadProcess2); 47 48 th1.join(); 49 th2.join(); 50 //マルチスレッド終了↑ 51 52 //ファイルオープン 53 FILE* fp; 54 errno_t error = fopen_s(&fp, "result.txt", "w"); 55 if (error != 0) return false; 56 57 //ファイル書き込み 58 char s_buf[BUFFSIZE]; 59 sprintf_s(s_buf, "sakura=%d, tomoyo=%d", sum_sakura, sum_tomoyo); 60 fputs(s_buf, fp); 61 62 //ファイルクローズ 63 fclose(fp); 64 65} 66 67//sakuraスレッド 68void ThreadProcess1() { 69 70 while (sum_apple <= 0) 71 { 72 //tomoyoを接客中なので何もしないで待つ 73 if (waiting == 1) 74 { 75 sakura_next_time--; 76 } 77 else //店員の手が空いてるとき 78 { 79 waiting = 1; 80 for (int i = 0; i < sakura_exchanging; i++) 81 { 82 if (sakura_next_time <= 0) 83 { 84 for (int j = 0; j < sakura_max; j++) 85 { 86 sum_sakura++; 87 sum_akira--; 88 if (sum_akira <= 0) break; 89 } 90 91 //next_timeリセット 92 sakura_next_time = sakura_turn_time; 93 } 94 } 95 waiting = 0; 96 } 97 if (sum_akira <= 0) break; 98 } 99 100 101} 102 103//tomoyoスレッド 104void ThreadProcess2() { 105 while (sum_apple <= 0) 106 { 107 //sakuraを接客中なので何もしないで待つ 108 if (waiting == 1) 109 { 110 tomoyo_next_time--; 111 } 112 else //店員の手が空いてるとき 113 { 114 waiting = 1; 115 for (int i = 0; i < tomoyo_exchanging; i++) 116 { 117 if (tomoyo_next_time <= 0) 118 { 119 for (int j = 0; j < sakura_max; j++) 120 { 121 sum_tomoyo++; 122 sum_akira--; 123 if (sum_akira <= 0) break; 124 } 125 126 //next_timeリセット 127 tomoyo_next_time = tomoyo_turn_time; 128 } 129 } 130 waiting = 0; 131 } 132 if (sum_akira <= 0) break; 133 } 134 135}

ちなみにヘッダーファイルは以下の通りです.
使ってないライブラリもあります.

C++

1#pragma once 2 3#pragma comment(lib, "winmm.lib") 4 5//インクルードライブラリ 6#include <windows.h> 7#include <mmsystem.h> 8#include <stdio.h> 9#include <stdlib.h> 10#include <time.h> 11#include <vector> 12#include <process.h> 13#include <thread> 14 15//マクロ宣言 16#define BUFFSIZE 1024 17 18//構造体宣言(客さくら,ともよ) 19typedef struct Customer { 20 int travel_time; //家から八百屋への片道時間 21 int home_time; //自宅での荷降ろし時間 22 int exchange_time; //八百屋での店員とのやり取り時間 23 int having_apple; //一度に購入できるりんごの数 24}; 25 26//構造体宣言(八百屋あきら) 27typedef struct Shop { 28 int all_apple; //販売りんご総数 29}; 30 31//グローバル変数宣言 32float sum_apple = 100; //残りりんご個数 33float waiting = 0; //店員の接客パラメータ(0で非接客中, 1で接客中) 34float sakura_next_time = 0; //sakuraが次にりんごを買いに来るまでの時間 35float tomoyo_next_time = 0; //tomoyoが次にりんごを買いに来るまでの時間 36float sakura_turn_time = 0; //sakuraの往復時間 37float tomoyo_turn_time = 0; //tomoyoがの往復時間 38float sakura_max = 0; //sakuraのりんご所持数限界 39float tomoyo_max = 0; //tomoyoのりんご所持数限界 40float sakura_exchanging = 0; //sakuraのやり取り時間 41float tomoyo_exchanging = 0; //tomoyoのやり取り時間 42float sum_sakura = 0; //sakuraのりんご現在所持数 43float sum_tomoyo = 0; //tomoyoのりんご現在所持数 44float sum_akira = 0; //akiraのりんご現在所持数 45 46//関数のプリ宣言 47void ThreadProcess1(); 48void ThreadProcess2();

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

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

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

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

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

guest

回答2

0

客は1人ずつしか対応できない

ここがひとつのキモです。リンゴの売買操作は八百屋の店員さん1人しか行えないので、その点を意識します。SakuraとTomoyoは八百屋で定員とやり取りするので、八百屋の中に入り、出るまでを八百屋の店員さんを占有する時間と考えてみましょう。また、リンゴが100個と言うのは八百屋側の都合であり、購入にあたってSakuraとTomoyoがどれだけ購入可能であるかは八百屋側にかかっているので、それも考慮した実装を例として挙げます。ファイルには出力していませんが、そこは本質ではないと考えましたので省いています。

C++

1#include <thread> 2#include <mutex> 3#include <cstdio> 4 5// 八百屋(店員)の排他ロックオブジェクト 6std::mutex store_mutex; 7 8// リンゴ在庫数 9int apple_num = 0; 10 11static void sleep(int seconds) { 12 std::this_thread::sleep_for(std::chrono::seconds(seconds)); 13} 14 15// リンゴの購入 - 在庫を考慮して買える個数を返す 16int buy_apple(int num_to_buy) { 17 int result = apple_num < num_to_buy ? apple_num : num_to_buy; 18 apple_num -= result; 19 return result; 20} 21 22void Sakura_worker() { 23 int total = 0; // 購入数 24 int turn = 0; // 購入回数 25 int num; 26 27 // リンゴが買える間、ループ 28 do { 29 ++turn; 30 31 printf("%d: Sakuraは %d 個のリンゴを購入済み.\n", turn, total); 32 // 家から店へ 33 sleep(1); 34 35 // 八百屋に入る (店員さんを占有) 36 store_mutex.lock(); 37 38 // リンゴを買える分、購入する 39 num = buy_apple(5); 40 41 // 八百屋で店員さんとやり取りする時間を消費 42 sleep(1); 43 44 // 八百屋から出る (店員さんを解放) 45 store_mutex.unlock(); 46 47 // 八百屋から家に帰る 48 sleep(1); 49 50 // 自宅での荷下ろし 51 sleep(3); 52 53 // 全購入数を更新 54 total += num; 55 } while (num > 0); 56 57 printf("Sakuraは %d 個のリンゴを購入できました.\n", total); 58} 59 60void Tomoyo_worker() { 61 int total = 0; // 購入数 62 int turn = 0; // 購入回数 63 int num; 64 65 // リンゴが買える間、ループ 66 do { 67 ++turn; 68 printf("%d: Tomoyoは %d 個のリンゴを購入済み.\n", turn, total); 69 sleep(2); 70 store_mutex.lock(); 71 num = buy_apple(3); 72 sleep(2); 73 store_mutex.unlock(); 74 sleep(2); 75 sleep(1); 76 total += num; 77 } while (num > 0); 78 79 printf("Tomoyoは %d 個のリンゴを購入できました.\n", total); 80} 81 82int main() 83{ 84 apple_num = 100; // リンゴの在庫を100にする 85 86 std::thread personA(Sakura_worker); 87 std::thread personB(Tomoyo_worker); 88 89 personA.join(); 90 personB.join(); 91 92 return 0; 93} 94

Visual Studio 2019 で確認しました。実行結果です。

CMD

1C:vct1>Debug\vct1.exe 21: Sakuraは 0 個のリンゴを購入済み. 31: Tomoyoは 0 個のリンゴを購入済み. 42: Sakuraは 5 個のリンゴを購入済み. 52: Tomoyoは 3 個のリンゴを購入済み. 63: Sakuraは 10 個のリンゴを購入済み. 73: Tomoyoは 6 個のリンゴを購入済み. 84: Sakuraは 15 個のリンゴを購入済み. 94: Tomoyoは 9 個のリンゴを購入済み. 105: Sakuraは 20 個のリンゴを購入済み. 115: Tomoyoは 12 個のリンゴを購入済み. 126: Sakuraは 25 個のリンゴを購入済み. 136: Tomoyoは 15 個のリンゴを購入済み. 147: Sakuraは 30 個のリンゴを購入済み. 157: Tomoyoは 18 個のリンゴを購入済み. 168: Sakuraは 35 個のリンゴを購入済み. 178: Tomoyoは 21 個のリンゴを購入済み. 189: Sakuraは 40 個のリンゴを購入済み. 199: Tomoyoは 24 個のリンゴを購入済み. 2010: Sakuraは 45 個のリンゴを購入済み. 2110: Tomoyoは 27 個のリンゴを購入済み. 2211: Sakuraは 50 個のリンゴを購入済み. 2311: Tomoyoは 30 個のリンゴを購入済み. 2412: Sakuraは 55 個のリンゴを購入済み. 2512: Tomoyoは 33 個のリンゴを購入済み. 2613: Sakuraは 60 個のリンゴを購入済み. 2713: Tomoyoは 36 個のリンゴを購入済み. 2814: Sakuraは 64 個のリンゴを購入済み. 29Tomoyoは 36 個のリンゴを購入できました. 30Sakuraは 64 個のリンゴを購入できました. 31 32C:vct1>

それぞれの立場で考えて分けてみると、マルチスレッドとは言えどもそれほど複雑な処理にならないことが分かると思います。

※余談ですが実は先のご質問C++ マルチスレッド - teratail#269460で ほぼC言語+ pthread で回答を用意していたのですが、愚直なコードなのでC++枠で参戦しそびれました。相変わらず愚直かもしれませんがこちらで質問者さんのコードに寄ったもので書き換え、回答してみた次第です。

投稿2020/06/12 11:36

dodox86

総合スコア9256

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

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

0

ベストアンサー

C++

1while (sum_apple <= 0)

sum_apple100なので、各スレッド一周も回らずに終わっていますよ。


C++

1 //next_time変数を自宅から店までの片道時間に初期化 2 float sakura_next_time = sakura.travel_time; //sakuraが次にりんごを買いに来るまでの時間 3 float tomoyo_next_time = tomoyo.travel_time; //tomoyoが次にりんごを買いに来るまでの時間

floatは不要です。初期化できていません。


C++

1sprintf_s(s_buf, "sakura=%d, tomoyo=%d", sum_sakura, sum_tomoyo);

floatに対して書式指定が%dになっています。


C++

1 while (sum_apple >= 0) 2 { 3 //省略 4 for (int j = 0; j < sakura_max; j++) 5 { 6 sum_sakura++; 7 sum_akira--; 8 if (sum_akira <= 0) break; 9 } 10 if (sum_akira <= 0) break; 11 }

sum_akiraは常に0以下の為、一周目でループを抜けてしまいます。


diff

1-for (int j = 0; j < sakura_max; j++) 2+for (int j = 0; j < tomoyo_max; j++)

ThreadProcess2のループ条件誤り?

投稿2020/06/11 16:18

編集2020/06/11 16:27
SHOMI

総合スコア4079

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

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

00_x9925

2020/06/12 04:08

回答ありがとうございます 最後のThreadProcess2のループ条件の誤りとはなんでしょうか?
SHOMI

2020/06/12 04:50

diffに書いてある通りです。sakura_maxとtomoyo_maxを間違えていませんか
dodox86

2020/06/12 09:25

>質問者さん まず、スレッドをひとつにして1行1行追ってデバッグしましょう。(コンパイルエラーが無いだけで、実際の処理を追っていないのでは?)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問