欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【操作系统】使用循环创建线程,一个手残导致的bug

程序员文章站 2022-06-19 10:59:25
...

让我们先看看这个手残的程序……

这是一个简单的生产者消费者问题。

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>


int buffer;
int count = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
pthread_cond_t fill = PTHREAD_COND_INITIALIZER;

void put(int value){
    assert(count == 0);
    buffer = value;
    count = 1;
}

int get(){
    assert(count == 1);
    count = 0;
    return buffer;
}

// gettid
pid_t get_thr_tid(){
    pid_t tid = syscall(__NR_gettid);
    return tid;
}

void* producer(void *arg){
    printf("producer(tid: %d) running\n", get_thr_tid());
    int loops = *(int *)arg; // gross product
    
    for(int i = 0; i < loops; i++){
        pthread_mutex_lock(&lock);
        while(count == 1){ // if the buffer is full,stop producing!
            pthread_cond_wait(&empty, &lock);
        }
        put(i);
        printf("produce(tid: %d): %d\n", get_thr_tid(), buffer);
        pthread_cond_signal(&fill); // Wake up the sleepy consumers.
        pthread_mutex_unlock(&lock);
    }

    return NULL;
}


void* consumer(void *arg){
    printf("                        consumer(tid: %d) running\n", get_thr_tid());

    int loops = *(int *)arg; // max consume counts
    
    for(int i = 0; i < loops; i++){
        pthread_mutex_lock(&lock);
        while(count == 0){ // if the buffer is empty,stop consuming!
            pthread_cond_wait(&fill, &lock);
        }
        int tmp = get(i);
        printf("                        consume(tid: %d): %d\n", get_thr_tid(), tmp);
        pthread_cond_signal(&empty); // Wake up the sleepy producers.
        pthread_mutex_unlock(&lock);
    }
    

    return NULL;
}



int main(int argc, char *argv[]){
    if(argc != 4){
        fprintf(stderr,"please input options: <loops> <producer_count> <consumer_count>\n");
        exit(1);
    }

    int loops = atoi(argv[1]);
    int producer_count = atoi(argv[2]);
    int consumer_count = atoi(argv[3]);

    printf("main thread running!\n");
    

    // create some threads
    pthread_t p[producer_count];
    pthread_t c[consumer_count];
    
    for(int i = 0; i < producer_count; i++){
        pthread_create(&p[producer_count], NULL, producer, (void *)&loops);
    }
    for(int i = 0; i < consumer_count; i++){
        pthread_create(&c[consumer_count], NULL, consumer, (void *)&loops);
    }

    
    for(int i = 0; i < producer_count; i++){
        pthread_join(p[producer_count], NULL);
    }
    for(int i = 0; i < consumer_count; i++){
        pthread_join(c[consumer_count], NULL);
    }

    printf("main thread done!\n");
    return 0;
}

这里最大的问题在后面创建和等待线程的时候

    for(int i = 0; i < producer_count; i++){
        pthread_create(&p[producer_count], NULL, producer, (void *)&loops);
    }
    for(int i = 0; i < consumer_count; i++){
        pthread_create(&c[consumer_count], NULL, consumer, (void *)&loops);
    }

    
    for(int i = 0; i < producer_count; i++){
        pthread_join(p[producer_count], NULL);
    }
    for(int i = 0; i < consumer_count; i++){
        pthread_join(c[consumer_count], NULL);
    }

本来很多地方应该使用i的!实际应该是这样:

    for(int i = 0; i < producer_count; i++){
        pthread_create(&p[i], NULL, producer, (void *)&loops);
    }
    for(int i = 0; i < consumer_count; i++){
        pthread_create(&c[i], NULL, consumer, (void *)&loops);
    }

    
    for(int i = 0; i < producer_count; i++){
        pthread_join(p[i], NULL);
    }
    for(int i = 0; i < consumer_count; i++){
        pthread_join(c[i], NULL);
    }

出于某种原因,楼主将后面的改正确了,前面不知道有问题,这就导致了下面的思考:


创建了线程pthread_t c[5]的数组,然后使用pthread_join()的时候,不是出现Segmentation fault就是出现pthread join error 3目前还不知道咋回事……

不知道为啥,使用数组就不行,单独创建多个变量就没事……

先在主线程使用pthread_exit(0)而不是return 0暂时避开问题了。


后来找了很多资料也没有解决,直到发现……线程创建一直在使用同一个pthread_t变量,并且使用同一个变量,创建了多个线程,而后面在没改之前,也是使用循环,等待了同一个变量多次……错错得对,这个程序居然可以正常运行

不清楚什么情况……后续再研究对于同一个pthread_t变量创建多个线程且等待多次的情况吧,就很神奇……

总结: 如果太手残,找bug会很心碎,因为你不知道你哪里手残了,且不是语法错误,而是逻辑错误,报错点也不是你手残的点。

!!

这里需要注意,对于pthread_join的报错,得联合看看,线程创建好了没有!是不是joinable的!

相关标签: Operating System