teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

2

質問に必要ない部分をカットしました。GitHubのソースコードも多少アップデートしています。

2020/07/26 02:27

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -2,66 +2,98 @@
2
2
 
3
3
  [GitHubのソースコード](https://github.com/egupiii/proj1)
4
4
 
5
- ### 前提
5
+ ### 発生している問題・エラーメッセージ
6
6
 
7
- ファイル構成は以下のようです
7
+ 期待する結果は以下の通りですが、
8
8
 
9
9
  ```
10
- – go.mod
11
- – twitter
12
- - twitter.go
10
+ {"success":true,"id":1}
11
+ {"success":true,"id":2}
12
+ {"success":true,"id":3}
13
- - tasks.json
13
+ {"success":false,"id":4}
14
- – feed
15
- - feed.go
16
- - queue
17
- - queue.go
14
+ {"success":true,"id":5}
18
- - lock
19
- - rwlock.go
15
+ {"success":false,"id":6}
16
+ {"id":7,"feed":[{"body":"Another post to add","timestamp":43242421}]}
20
17
  ```
21
18
 
22
- まず、feed.goにはLinkedListが実装してありますが、これは、あるTwitterユーザー投稿ようなもだと思っください。
19
+ 以下コマンドで2つのサブスレッドを発生させると(つ目コマンド引数がスレッド数です。)、デッドロックを起こししまます
23
20
 
24
- queue.goには、非有界のロックフリーなキューが実装してあります。このキューは、実行したいタスクを格納しているものです。tasks.jsonファイルをみてもらいたいのですが、一行目の
25
- ```JSON
26
- {"command": "ADD", "id": 1, "body": "just setting up my twttr", "timestamp": 43242423}
27
21
  ```
22
+ $ twitter kazukiegusa$ go run twitter.go 2 4 < tasks.json
23
+ {"success":true,"id":1}
24
+ {"success":true,"id":2}
25
+ {"success":true,"id":3}
26
+ {"success":false,"id":4}
27
+ {"success":false,"id":6}
28
- は、"just setting up my twttr"という投稿を、ユーザーの投稿一覧に"ADD"する(追加する)タスクを意味しています。
28
+ {"id":7,"feed":[{"body":"Another post to add","timestamp":43242421}]}
29
+ fatal error: all goroutines are asleep - deadlock!
29
30
 
31
+ goroutine 1 [semacquire]:
32
+ sync.runtime_Semacquire(0xc000016088)
33
+ /usr/local/go/src/runtime/sema.go:56 +0x42
30
- メインの質問にはあまり関係ないので、説明はこれぐらいにしておきます。
34
+ sync.(*WaitGroup).Wait(0xc000016080)
35
+ /usr/local/go/src/sync/waitgroup.go:130 +0x64
36
+ main.main()
37
+ /Users/kazukiegusa/mpcs/Parallel Programming/egusa/proj1/twitter/twitter.go:66 +0x422
38
+ exit status 2
39
+ ```
31
40
 
32
41
  ### 実現したいこと&わからないこと
33
42
 
34
- まず、twitter.go内の、メインのgoroutineがサブgoroutineを発生させて、それぞれのサブgoroutineがconsumer関数を実行します。全てサブgoroutineを発生させたらメイのgoroutineがproducer関数を実行します。
43
+ 質問の箇所は`twitter.go`にあります。まず、`main`関数中でディション変数を定義ています。
35
44
 
45
+ ```Go
36
- cosumer関数のでは、各サブgoroutineが、キューから一定の数のタスクを取ってきて、それを実行していくのですが、もしキューが空の場合は、そのサブgoroutineを待機させたいです。(最初に発生させたサブgoroutine以外は発生させません。)ここで、待機させるのは、sync.CondのWait()を使えばいいのでしょうか?
46
+ ・・・略・・・
37
47
 
38
- producer関数の中では、メインのgoroutineがタスクをキューにどんどん格納していくのですが、タスクをキューに入れるたびに、Wait()しているサブのgoroutineがないか確認して、ある場合は一つ起こします。一つだけ起こすので、sync.CondのSignal()を使うのであっていますでしょうか?
48
+ var wg sync.WaitGroup
39
49
 
40
- ### 発生している問題・エラーメッセージ
50
+ cond := sync.NewCond(new(sync.Mutex)) // Conditional variable
41
51
 
42
- スレッドを使わず、メインのgoroutineのみに処理をさせる場合は以下の形です。
52
+ for i := 0; i < numGoroutines; i++ {
53
+ wg.Add(1)
54
+ go consumer(q, f, blockSize, cond, &wg)
55
+ }
43
56
 
57
+ producer(q, cond)
58
+
59
+ // 全てのサブスレッドがconsumer関数の実行を終えるまで待つ
60
+ wg.Wait()
44
61
  ```
62
+
45
- $ go run twitter.go < tasks.json
63
+ `producer`関数の中では、エンキュー(Enqueue)するごとに、`sync.Cond`の`Signal`関数を使って、`consumer`関数内で待機しているスレッドを一つ呼び起こしています。
64
+
46
65
  ```
66
+ func producer(q *queue.Queue, cond *sync.Cond) {
47
67
 
48
- 実行結果は、
68
+ ・・・中略・・・
49
69
 
70
+ for {
71
+
72
+ ・・・中略(ここにエンキュー(Enqueue)を実行するコードが入ります。)・・・
73
+
74
+ // 待機中のサブスレッドを一つ呼び起こす
75
+ cond.Signal()
76
+ }
77
+ }
50
78
  ```
51
- {"success":true,"id":1}
79
+
52
- {"success":true,"id":2}
53
- {"success":true,"id":3}
54
- {"success":false,"id":4}
80
+ `consumer`関数内では、初期化するときに`sync.Cond`に紐付けたMutexを使ってロックしています。
55
- {"success":true,"id":5}
81
+
56
- {"success":false,"id":6}
57
- {"id":7,"feed":[{"body":"Another post to add","timestamp":43242421}]}
58
82
  ```
83
+ func consumer(q *queue.Queue, f feed.Feed, blockSize int64, cond *sync.Cond, wg *sync.WaitGroup) {
59
84
 
60
- 本題です。以下のコマンドで2つのサブスレッドを発生させることが出来るのですが、何も返さず、上記のような結果が出ません。
85
+ cond.L.Lock()
61
86
 
87
+ // キューが空なら待機する
88
+ cond.Wait()
89
+
90
+ ・・・中略(ここにデキュー(Dequeue)を実行するコードが入ります。)・・・
91
+
92
+ cond.L.Unlock()
93
+
94
+ wg.Done()
95
+ }
62
96
  ```
63
- $ go run twitter.go 2 10 < tasks.json
64
- ```
65
97
 
66
98
  ### 試したこと
67
99
 

1

多少説明を追加しました。

2020/07/26 02:27

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -33,11 +33,10 @@
33
33
 
34
34
  まず、twitter.go内の、メインのgoroutineがサブgoroutineを発生させて、それぞれのサブgoroutineがconsumer関数を実行します。全てのサブgoroutineを発生させたら、メインのgoroutineがproducer関数を実行します。
35
35
 
36
- cosumer関数の中では、各サブgoroutineが、キューから一定の数のタスクを取ってきて、それを実行していくのですが、もしキューが空の場合は、待機させたいです。(最初に発生させたgoroutine以外は、サブgoroutineをこれ発生させません。)ここで、待機させるのは、sync.CondのWait()を使えばいいのでしょうか?
36
+ cosumer関数の中では、各サブgoroutineが、キューから一定の数のタスクを取ってきて、それを実行していくのですが、もしキューが空の場合は、そのサブgoroutineを待機させたいです。(最初に発生させたサブgoroutine以外は発生させません。)ここで、待機させるのは、sync.CondのWait()を使えばいいのでしょうか?
37
37
 
38
38
  producer関数の中では、メインのgoroutineがタスクをキューにどんどん格納していくのですが、タスクをキューに入れるたびに、Wait()しているサブのgoroutineがないか確認して、ある場合は一つ起こします。一つだけ起こすので、sync.CondのSignal()を使うのであっていますでしょうか?
39
39
 
40
-
41
40
  ### 発生している問題・エラーメッセージ
42
41
 
43
42
  スレッドを使わず、メインのgoroutineのみに処理をさせる場合は以下の形です。
@@ -58,7 +57,7 @@
58
57
  {"id":7,"feed":[{"body":"Another post to add","timestamp":43242421}]}
59
58
  ```
60
59
 
61
- 本題です。以下のコマンドでスレッドを発生させることが出来るのですが、何も返さず、上記のような結果が出ません。
60
+ 本題です。以下のコマンドで2つのサブスレッドを発生させることが出来るのですが、何も返さず、上記のような結果が出ません。
62
61
 
63
62
  ```
64
63
  $ go run twitter.go 2 10 < tasks.json