C pthread似乎没有使用更新的全局数据值

C pthread似乎没有使用更新的全局数据值,c,linux,multithreading,pthreads,C,Linux,Multithreading,Pthreads,我是个新手。我想让两个线程xthread打印“X”;和ythread打印“Z”;持续,直到用户在stdin处插入'C'或'C'。我使用select检查是否有任何userinput。如果有用户输入,我使用scanf在read中获取它并进行比较 我一直把读为全球的。[是否有其他方式在线程之间共享非全局数据?]。我假设,当用户在stdin中输入'c'时,当前运行的线程将读取它并将其存储在读取和中断中。我已经使用标志read\u input向其他线程指示输入已经被获取,您不需要再次获取userinput

我是个新手。我想让两个线程
xthread
打印“X”;和
ythread
打印“Z”;持续,直到用户在
stdin
处插入
'C'
'C'
。我使用select检查是否有任何userinput。如果有用户输入,我使用
scanf
read
中获取它并进行比较

我一直把
读为全球的。[是否有其他方式在线程之间共享非全局数据?]。我假设,当用户在stdin中输入
'c'
时,当前运行的线程将读取它并将其存储在
读取和中断中。我已经使用标志
read\u input
向其他线程指示输入已经被获取,您不需要再次获取userinput

问题

用户输入
'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;
}
#包括
#包括
#包括
静态无符号整数i=0;
字符读取;
int read_输入=0;
作废*打印(作废*参数)
{
int fd=文件号(标准输入);
结构timeval tv={0,0};
fd_集fdset;
int-s;
char*buffer=NULL;
无符号整数len;
而(1)
{
结构timespec t={0433300000};
const struct timespec*tp=&t;
纳米睡眠(tp和t);
printf(“\n读取值为%d”,已读取);
//睡眠(1);
FD_零点(&fdset);
FD_集(FD和FD集);
printf(“\n%p打印%c,i是%d”,pthread_self(),*((char*)arg),i++);
if((s=select(fd+1,&fdset,NULL,NULL,&tv))==1)
{
printf(“\n s的值为%d”,s);
如果(!读取输入)
scanf(“%c”,读取(&R));
fflush(stdin);
printf(“\n读取值为%d”,已读取);
printf(“\n为%d或%d检查,'C','C');
如果(读=='C'| |读=='C')
{
读取输入=1;
打破
}
}
printf(“\nHere”);
}
printf(“\nI,%p存活,而(1)”,pthread_self();
返回NULL;
}
int main()
{
pthread_t xthread、ythread、checkThread;
字符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);
返回0;
}
如果有更好的方式获取用户输入,请告诉我。 我不知道使用
pthread\u cond\t
是否能解决我的问题。我觉得没有必要使用互斥。[如果我错了,请纠正我]

线程之间是否有其他共享非全局数据的方法

是的,它被称为IPC(进程间通信) 并且可以将它与pthreads一起使用。 这包括:套接字、管道、共享内存等


关于程序本身,正如Daniel Fischer在评论中写道的那样,read_输入不是易变的,因此编译器可以自由地对其进行优化。

编译器优化
read
读取的可能性(顺便说一句,如果一个人想
#包括
),因为它不是易变的

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;
    }
}
您的测试将在
if(选择(…)
内的
while(1)
循环中中断

因此,在第一个线程读取一个
'C'
'C'
并退出后,另一个线程只会在
stdin
提供新输入时检查条件(在我的系统中,需要按下返回键)

将该条件移到
if(选择(…)
之外,使第二个线程有机会退出,而无需
select
报告更多的输入可用

而且


这是一种未定义的行为。尽管有几个实现承诺它会做一些明智的事情,但您不应该依赖它。

您的代码的主要问题是
read
不像Daniel所说的那样是易变的。这意味着编译器不知道它可以像另一个线程一样被不可预见的外力改变

除此之外,您的代码还有很多错误和错误做法:

  • 不要定义具有标准库名称等效项的符号,如
    read
  • 不要在多个线程中对同一文件描述符使用
    select
    。这是灾难的秘诀。如果两个线程同时从select返回,它们都将尝试从
    stdin
    读取,并且只有一个线程将成功,另一个线程将阻塞。如果要使用文件描述符进行同步,请将其设置为非阻塞并使用
    read
    ,这不是信号安全的,但比满量程竞争条件更好
  • 始终首先包括
    pthread.h
  • 您是否知道您正在以非原子方式递增
    i
    (竞争条件)?我没有改变这一点,但是
    \uuu同步\uu获取\u和\uu添加
    会自动完成这一任务
这是一种方式:

#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;
}
#包括
#包括
#包括
#包括
静态无符号整数i=0;
易失性字符读取;//必须是易失性的,因为您正在用两个线程检查它
volatile int read_input=0;//必须是不稳定的
作废*打印(作废*参数)
{
//int fd=文件号(标准输入);
int fd=0;//stdin始终为0
而(1)
{
结构timespec t={0433300000};
const struct timespec*tp=&t;
纳米睡眠(tp和t);
printf(“\n读取值为%d”,字符读取);
printf(“\n%p打印%c,i是%d”,pthread_self(),*((char*)arg),i++);
if(read_input | | scanf(“%c”,&char_read)>0)//尝试读取1个字节
{
//printf(“\n s的值为%d”,s);
printf(“\n读取值为%d”,字符读取);
printf(“\n已检查%d或
#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;
}
/*2--->*/   if(!read_input)
        {
/*3--->*/   if((s = select(fd+1, &fdset, NULL, NULL, &tv)) == 1)
            {
            printf("\nValue of s is %d",s);
//1---->        if(!read_input) 
                printf("\nValue of read is %d",read);
                printf("\nChecked for %d or % d",'C','c');
                if(read == 'C' || read == 'c')
                {
                    read_input = 1;
                    break;
                }
            }
        }
/*4--->*/   else
            break;
        printf("\nHere");
    }
    printf("\nI, %p survived while(1)",pthread_self());
}