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

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

ただいまの
回答率

88.61%

WorkerThreadが2個目以降のキューを実行しません。

受付中

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 1,670
退会済みユーザー

退会済みユーザー

WorkerThreadを用いたプログラムを作成しております。

概要

  • リストコマンドラインに入力された数字によって動作を変更し、
    サブスレッドで入力され次第随時実行していきます。
  • キューには連結リストを使用しています。

環境
VMware 7.1.4 build-3848939
Unbuntu Linux

#define _CRT_SECURE_NO_WARNINGS

#include "stdlib.h"
#include "stdio.h"
#include "pthread.h"
#include "CheckFile.h"
#include "Integration.h"
#include "Analysis.h"
#include "AddList.h"
#include "freeListPointer.h"
#include "define.h"

typedef struct Queue
{
    int action;
    struct Queue *next;
    struct Queue *prev;
}Queue;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t MainCond;
pthread_mutex_t EventMutex;



void *SubThread(void *p_arg);

//Global Variable for End SubThread.
int SubThreadEnd = 0;

//Global Variable for count queue number.
int count = 0;

//Global Pointer Valiable for keep head pointer of queue.
Queue *head = NULL;

//Global Variable for end programs.
int EndCount = 0;

Queue *Enqueue(int action, Queue *p)
{

    pthread_mutex_lock(&EventMutex);
    Queue *ptr = (Queue *)malloc(sizeof(Queue));

    if(NULL == ptr)
    {
        printf("Could not get memory area.\n");
    }

    if(p == NULL)
    {
        head = ptr;
        ptr->action = action;
        ptr->prev = NULL;
        ptr->next = NULL;
        pthread_mutex_unlock(&EventMutex);
        return ptr;
    }

    ptr->action = action;
    p->next = ptr;
    ptr->prev = p;
    ptr->next = NULL;

    count++;

    pthread_mutex_unlock(&EventMutex);
    return ptr;

}
void Action(int action)
{    
    if(action == 1)
    {
    }
    if(action == 2)
    {
    }
    if(action == 3)
    {
    }
//処理は省きます。

void *SubThread(void *p_arg)
{
    int loop = 0;


    printf("SubThread - Starting.\n");

    while(1)
    {
        while(NULL != head)
        {
            pthread_mutex_lock(&EventMutex);

            //Dequeue by excuting the function.
            Action(head->action);
            head = head->next;

            pthread_mutex_unlock(&EventMutex);
            pthread_cond_signal(&MainCond);    
        }

    }
}

void main()
{
    pthread_t th;
    int action = 0;
    Queue *p = NULL;

    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    pthread_create(&th,NULL,SubThread,NULL);

    pthread_cond_init(&MainCond, NULL);
    pthread_mutex_init(&mutex, NULL);

    while(1)
    {

        printf("Select the action.\n");
        printf("(1).Loading file.\n");
        printf("(2).Select analysis method.\n");
        printf("(3).Exit programs.\n");

        scanf("%d",&action);

        p = Enqueue(action,p);

        pthread_cond_wait(&MainCond,&mutex);

        if(EndCount != 0)
        {
            break;
        }

    }
    printf("Exit program.\n");
}

実行後、1回目の入力では、正常にサブスレッドが機能していることが確認されたのですが、
2回目以降、main関数でコマンドラインより入力を行うとEnqueueを実行し終わったところで
プログラムがとまってしまいます。(エラーなどによる動作停止ではなく、メインでwaitして
いるのにサブスレッドが動きません。)

なぜサブスレッドは無限ループにしているにもかかわらずとまってしまっているのでしょうか。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

0

条件変数(pthread_cond_t)の使い方を誤っています。

  • メインスレッド→サブスレッドに通知する設計ですから、メインスレッド側がSignal、サブスレッド側がWaitする構造になるべきです。 
  • pthread_cond_wait(cv,m)関数は、第2引数に指定したミューテックスのロックを保持した状態、つまりpthread_mutex_lock(m)pthread_mutex_unlock(m)区間の中で呼び出す必要があります。

手前味噌ですが 条件変数 Step-by-Step入門 にて正しい使い方を解説しています。ご参考までに。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/09 11:39 編集

    回答ありがとうございます。

    lock→wait→signalでunlockという流れだったのですね。
    使い方を誤っていました。

    省いてしまっているのですが、Action関数内の処理にファイル名を入力する処理を設けています。
    yohhoyさんがおっしゃったように、SubThread側でwaitさせ、main関数でsignalを出すと言う方法で行うと、main関数がsignalでlock/waitしているSubThread起こした際、ファイル名の入力を行います。するとmain関数でのwhile内のscanfが当然同時に処理されているわけですが、ファイル入力の際、(サブスレッドが終了するまで)メインスレッドをとめる方法はありますでしょうか。

    main 数字入力

    subthread 受け取って処理(ここでファイル名の入力も行います)

    main数字入力

    subthread 受け取って処理(ここでファイル名の入力も行います)
    ...
    というように処理をしたいのです。

    scanfのあとlock・waitさせ、SubThreadが終了すればmainにsignalを返すという方法を思いついたのですが、signalを打ち合っていてわけが分からなくなるといわれてしまいました。

    この方法は良くないのでしょうか。 また違った解決策があればご教授願いたいです。

    サイト拝見しました。
    しかし、C++を触ったことが無いので、説明をコードで落とし込むことがあまり出来ませんでした・・
    せっかく記載してくださったのに申し訳ありません・・・

    キャンセル

  • 2017/06/09 11:47 編集

    (断言はできませんが)signal/waitの仕組みを勘違いされているようにも思えます... また、メインスレッド/サブスレッドの両方が同種I/O(ここではキー入力)を待ち受ける構造にも違和感があります。

    pthreadで説明している良い資料はあまり見つからない気がしますが、書籍「Pthreadsプログラミング」 https://www.oreilly.co.jp/books/4900900664/ は参考になるかと思います。(というより他に良い情報源を知りません)

    キャンセル

  • 2018/06/08 02:42 編集

    producer-consumer queue やね。
    C++でのサンプルなら
    https://codezine.jp/article/detail/10657
    ってのを書きました。

    キャンセル

  • 2018/06/08 13:16

    (codezineは非会員でも読めると嬉しいんですけどねー; ここで言っても詮無いお話)

    キャンセル

0

pthread関連で色々と問題があるとは思いますが、このプログラムが動かない原因はそこではありません。
一度、SubThread内のループを通るとheadがNULLとなり、以降、NULL以外の値になることがないために、SubThread内の処理が実行されません。
pthread関連の見直しと共に、キューの扱いについても、考え直した方がよいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

Harahiraさんの指摘が正しいと思います。その背景は、結構自明に見えるheadの扱いかたの計画が緩いのではないかと思います。Enqueueの方も、もう少し簡単になります。

Queue *Enqueue(int action, Queue *p) {

    pthread_mutex_lock(&EventMutex);
    Queue *ptr = (Queue *)malloc(sizeof(Queue));

    if(p == NULL) p = head ;
    p->next = ptr;
    ptr->action = action;
    ptr->prev = p;
    ptr->next = NULL;
    count++;
    pthread_mutex_unlock(&EventMutex);
    return ptr;

}


たぶんheadの値は一度決めたら変更してはいけないのではないかと思います。
使用済のキューを捨てるなら、free の必要があります。
効率的にthreadするなら、

  1. quequeの管理は一か所に集める。queを足す関数、使う関数だけにqueueの扱いを任せる。
  2. mallocでqueueを足すときに、1つづつではなくて、100個くらいpoolしておいて、queueを数珠つなぎにする処理をactionの処理と並列実行するようにする。
    みたいなふうに考えたほうがいいです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る