0

私はスレッドが初めてです。xthread2 つのスレッドに 'X' を出力させたい。そしてythread「Z」を出力します。'C'ユーザーがまたは'c'at を挿入するまで継続しstdinます。select を使用して、ユーザー入力があるかどうかを確認しました。ユーザー入力がある場合は、それscanfを取得しreadて比較を行います。

私はreadグローバルのままにしています。[スレッド間で非グローバル データを共有する他の方法はありますか? ] . 'c'ユーザーが標準入力に入力すると、現在実行中のスレッドがそれを読み取り、に保存すると仮定しましたread and breaks out。フラグread_inputを使用して、入力が既に取得されており、ユーザー入力を再度取得する必要がないことを他のスレッドに示しました。

問題:

ユーザーが入力'c'

xthread 終了 [または ythread]

ただし、ythread はループし続け、'c'再度入力した後にのみ終了します。[私の推測では、以前の値を読み取り、read比較のために同じ値を使用しています]

私は何を間違えましたか?

#include<stdio.h>
#include<sys/select.h>
#include<pthread.h>
static unsigned int i =0;
char read;
int read_input = 0;

void* print_fn(void* arg)
{
    int fd = fileno(stdin);
    struct timeval tv = {0,0};
    fd_set fdset;
    int s;
    char *buffer = NULL;
    unsigned int len;

    while(1)
    {
        struct timespec t = {0,433300000};
        const struct timespec * tp = &t;
        nanosleep(tp,&t);

        printf("\nValue of read is %d",read);

        //sleep(1); 
        FD_ZERO(&fdset);
        FD_SET(fd, &fdset);
        printf("\n%p prints %c and i is %d",pthread_self(),*((char*)arg),i++);  
        if((s = select(fd+1, &fdset, NULL, NULL, &tv)) == 1)
        {
            printf("\nValue of s is %d",s);
            if(!read_input)
                scanf("%c",&read);
            fflush(stdin);
            printf("\nValue of read is %d",read);
            printf("\nChecked for %d or % d",'C','c');
            if(read == 'C' || read == 'c')
            {
                read_input = 1;
                break;
            }
        }
        printf("\nHere");
    }
    printf("\nI, %p survived while(1)",pthread_self());
    return NULL;
}

int main()
{

pthread_t xthread,ythread,checkThread;  
char c1 = 'X', c2 = 'Z';
pthread_create(&xthread,NULL,print_fn,&c1);
pthread_create(&ythread,NULL,print_fn,&c2);
pthread_join(xthread,NULL);
pthread_join(ythread,NULL);

return 0;
}

ユーザー入力を取得するより良い方法がある場合は、お知らせください。pthread_cond_tを使用することで問題が解決するかどうかはわかりません。ミューテックスを使用する必要はありません。【間違っていたら訂正】

4

4 に答える 4

1

コンパイラーがread(ちなみに、必要に応じて悪い名前)の読み取りを最適化する可能性は、それが脇に#include <unistd.h>ないために、volatile

if((s = select(fd+1, &fdset, NULL, NULL, &tv)) == 1)
{
    printf("\nValue of s is %d",s);
    if(!read_input)
        scanf("%c",&read);
    fflush(stdin);
    printf("\nValue of read is %d",read);
    printf("\nChecked for %d or % d",'C','c');
    if(read == 'C' || read == 'c')
    {
        read_input = 1;
        break;
    }
}

while(1)内のループを壊すテストがありますif(select(...))

したがって、最初のスレッドが'C'or'c'を読み取って終了した後、他のスレッドは新しい入力が利用可能な場合にのみ条件をチェックしますstdin(私のシステムではReturnキーを押す必要があります)。

その条件if (select(...))を 2 番目のスレッドの外に移動してselect、追加の入力が利用可能であることを報告せずに終了できるようにします。

また、

fflush(stdin);

未定義の動作です。いくつかの実装は、それが賢明なことを行うことを約束していますが、それに頼るべきではありません。

于 2013-04-02T14:15:01.840 に答える
0

あなたのコードの主な問題は、ダニエルが言った通りでreadはないということです。volatileこれは、コンパイラが、別のスレッドのような予測不可能な外力によって変更される可能性があることを認識していないことを意味します。

それとは別に、あなたのコードには多くのエラーと悪い習慣があります:

  • のような標準の lib 名に相当するシンボルを定義しないでくださいread
  • select複数のスレッドで同じファイル記述子に対して使用しないでください。これは災害のレシピです。両方のスレッドが選択から同時に戻った場合、両方が読み取りを試み、stdin一方のみが成功し、もう一方はブロックされます。同期にファイル記述子を使用する場合は、非ブロッキングに設定して を使用しますread。これはシグナルセーフではありませんが、本格的な競合状態よりはましです。
  • 常にpthread.h最初に含めます。
  • i非アトミック (競合状態) でインクリメントしていることに気付いていますか? 私はそれを変更しませんでしたが、__sync_fetch_and_addアトミックにトリックを行います。

これは方法です:

#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

static unsigned int i =0;
volatile char char_read; // has to be volatile since you are checking it with both threads
volatile int read_input = 0; // has to be volatile

void* print_fn(void* arg)
{
    // int fd = fileno(stdin);
    int fd = 0; // stdin is always 0

    while(1)
    {
        struct timespec t = {0,433300000};
        const struct timespec * tp = &t;
        nanosleep(tp,&t);

        printf("\nValue of read is %d",char_read);

        printf("\n%p prints %c and i is %d",pthread_self(),*((char*)arg),i++);  
        if(read_input || scanf("%c",&char_read) > 0) // attempt to read 1 byte
        {
            // printf("\nValue of s is %d",s);
            printf("\nValue of read is %d",char_read);
            printf("\nChecked for %d or % d",'C','c');
            if(char_read == 'C' || char_read == 'c')
            {
                read_input = 1;
                break;
            }
        }
        printf("\nHere");
    }
    printf("\nI, %p survived while(1)\n",pthread_self());
    return NULL;
}

int main()
{
    // make stdin non-blocking
    fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);

pthread_t xthread,ythread,checkThread;  
char c1 = 'X', c2 = 'Z';
pthread_create(&xthread,NULL,print_fn,&c1);
pthread_create(&ythread,NULL,print_fn,&c2);
pthread_join(xthread,NULL);
pthread_join(ythread,NULL);

return 0;
}
于 2013-04-02T14:15:28.900 に答える