意外的pthread输出

时间:2016-12-24 15:24:10

标签: c

好的,所以我正在尝试编写一个基本程序,它将创建共享资源的“读者”和“编写者”线程,并尽可能优先于作者。我使用互斥结构保护此资源,但代码的行为不是我所期望的。我已将问题追溯到我的代码的一行,但我无法理解为什么它不起作用! “bug”并不总是发生,这是线程所期望的,但是当它确实发生时,我找不到合适的解释! 这是我的计划:

Function GetIPAddress: String;
type pu_long = ^u_long;
var varTWSAData : TWSAData;
varPHostEnt : PHostEnt;
varTInAddr : TInAddr;
namebuf : Array[0..255] of ansichar;
begin
try
try
If WSAStartup($101,varTWSAData) <> 0 Then
Result := ''
Else Begin
gethostname(namebuf,sizeof(namebuf));
varPHostEnt := gethostbyname(namebuf);
varTInAddr.S_addr := u_long(pu_long(varPHostEnt^.h_addr_list^)^);
Result := inet_ntoa(varTInAddr);
End;
except
Result := '';
end;
finally
WSACleanup;
end;
end;

查看该行(在reader_job中)reader_queue_length ++;,我不明白为什么当该行在互斥锁之外时该程序不起作用,但是当它在内部时它可以工作!输出让我更加困惑,因为“bug”发生在最后(在这个特定的运行实例中,见下文),当所有线程都已经加入时,因此没有人留下来改变我的变量,对吧?! / p>

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

#define N 3 //Number of readers.
#define M 3  //Number of writers.
#define X 2  //Number of times a reader reads.
#define Y 2  //Number of times a writer writes.

pthread_mutex_t res_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t res_cond_read = PTHREAD_COND_INITIALIZER;
pthread_cond_t res_cond_write = PTHREAD_COND_INITIALIZER;
int resource = 0, state = 0 /*1 = writing, 0 = waiting, abs(<0) = #readers*/, reader_queue_length = 0;

void *reader_job (void* parg);
void *writer_job (void* parg);

int main ()
{       
    srandom((unsigned int)time(NULL));

    pthread_t readers[N];
    pthread_t writers[M];   
    int valueR[N], valueW[M];

    //printf ("NOTICE: Reader queue lengths excluding current thread.\n");
    for (int i=0; i<N; i++) {       
        valueR[i] = i;
    }

    for (int i=0; i<M; i++) {       
        valueW[i] = i;
    }   
    for (int i=0; i<N; i++) {       
        pthread_create (&readers[i], NULL, reader_job, &valueR[i]);                     
    }

    for (int i=0; i<M; i++) {
        pthread_create (&writers[i], NULL, writer_job, &valueW[i]);
    }

    for (int i=0; i<N; i++) {
        pthread_join (readers[i], NULL);        
    }

    for (int i=0; i<M; i++){
        pthread_join (writers[i], NULL);
    }
    return 0;
}

void *reader_job (void* parg) {
    int *temp = (int*) parg;
    int value = *temp;  
    int local_read_num = 0;
    printf (">>> Creating reader: %d\n", value);
    while (local_read_num < X) {
        usleep(1000 * (random() % (N+M)));              
        reader_queue_length++; //When this line is here, wrong.
        printf ("INFO::About to access entry mutex for reader with ID: %2d, with queue length %2d.\n",
            value, reader_queue_length);
        pthread_mutex_lock(&res_mutex);
            //reader_queue_length++; //When it is here, right.
            if (reader_queue_length == 0) printf ("\nERROR::Before entry mutex!\n\n");          
            while (state != 0)
                pthread_cond_wait (&res_cond_read, &res_mutex);
            state--;
            if (reader_queue_length == 0) printf ("\nERROR::During entry mutex!\n\n");
            reader_queue_length--;
            printf ("INFO::About to exit entry mutex for reader with ID: %2d, with queue length %2d.\n",
                value, reader_queue_length);
        pthread_mutex_unlock (&res_mutex);

        printf ("[READER (ID: %2d):] Readers in queue: %2d, read: %2d\n", value, reader_queue_length, resource);

        pthread_mutex_lock (&res_mutex);
            state++;
            pthread_cond_signal (&res_cond_read);
            if (reader_queue_length == 0) pthread_cond_signal (&res_cond_write);                        
        pthread_mutex_unlock (&res_mutex);


        local_read_num++;
    }
    printf ("!!! Destroying reader: %d\n", value);
    pthread_exit (NULL);
}

void *writer_job (void* parg) {
    int *temp = (int*) parg;
    int value = *temp;  
    int local_write_num = 0;
    printf (">>> Creating writer: %d\n", value);
    while (local_write_num < Y) {
        //usleep(1000 * (random() % (N+M)));
        pthread_mutex_lock(&res_mutex);
            while (state != 0 || reader_queue_length > 0)
                pthread_cond_wait (&res_cond_write, &res_mutex);    
            state++;
        pthread_mutex_unlock(&res_mutex);

        resource = value*5+local_write_num;
        printf ("[WRITER (ID: %2d):] Readers in queue: %2d, wrote: %2d\n", value, reader_queue_length, resource);

        pthread_mutex_lock (&res_mutex);
            state--;
        pthread_mutex_unlock(&res_mutex);

        pthread_cond_signal(&res_cond_read);
        pthread_cond_signal(&res_cond_write);
        local_write_num++;
    }
    printf ("!!! Destroying writer: %d\n", value);
    pthread_exit (NULL);
}

读者队列如何以负长度结束?哪个线程可以改变内容?它们都已经被破坏了,或者至少超过了它们可以搞乱变量的运行周期中的点!

仅供参考我在Ubuntu 16.04上使用gcc编译器和-pthread标志运行它。

提前谢谢大家!

1 个答案:

答案 0 :(得分:1)

好吧,所以我认为这就是问题:当我尝试在互斥锁之外编辑队列长度变量时,会发生多个线程尝试一次访问同一个变量,导致数据竞争!

例如,如果变量的值为A,并且尝试访问它的命令尝试将值编辑为A + 1,则可能是尝试访问变量的线程全部加载初始值A,没有正确地等待彼此编辑变量然后获取更新的值。因此,在进入互斥锁之前,它们都会以值A + 1结束,这会导致“错误”。

底线:该命令需要在互斥锁内!