代码之家  ›  专栏  ›  技术社区  ›  AshR

程序断断续续地使用main报告与线程本身不同的线程id

  •  0
  • AshR  · 技术社区  · 6 年前

    我正在试图弄清楚多线程是如何工作的,下面是我的代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <string.h>
    #include <pthread.h>
    
    static pthread_cond_t threadDied = PTHREAD_COND_INITIALIZER ; // cond var initialization
    static pthread_mutex_t threadMutex = PTHREAD_MUTEX_INITIALIZER ; // mutex initialization
    // this mutex will protect all of the below global vars
    
    static int totThreads = 0 ; // total number of threads created
    static int numLive = 0 ;   // Total no. of threads still alive .. or terminated but not joined
    static int numUnjoined = 0 ; // no. of threads that have not yet been joined
    
    enum tstate { // enumeration of thread states
        TS_ALIVE, // thread is alive
        TS_TERMINATED, // thread terminated, not yet joined
        TS_JOINED  // thread terminated and joined
    };
    
    static struct {  // info about each thread
        pthread_t tid ; // thread ID
        enum tstate state; // Thread state as per the above enum
        int sleepTime ;  // no. of seconds to live before terminating
    } *thread ; // name of the struct .. well a pointer
    
    static void *threadFunc (void *arg) { // default start function for each thread
        int idx = *(int *)arg  ; // since arg is of type void , we typecast it to * of type int and deref it
        int s ; // for ret val
    
        sleep(thread[idx].sleepTime) ;  // pretending as though thread is doing some work :/
    
        s = pthread_mutex_lock(&threadMutex);
        if (s!=0) {
            printf("whoops, couldn't acquire mutex\n") ;
            fflush(stdout);
            exit (-1) ;
        }
    
        numUnjoined ++ ;
        thread[idx].state = TS_TERMINATED ;
    
        s = pthread_mutex_unlock(&threadMutex) ;
        if ( s!=0 ) {
            printf("whoops, couldn't release mutex\n") ;
            fflush(stdout);
            exit (-2) ;
        }
    
        s = pthread_cond_signal(&threadDied) ; // signalling any listening thread to wake up !!
        if (s != 0) {
            printf("whoops, couldn't signal the main thread to reap\n");
            fflush(stdout);
            exit (-3) ;
        }
        printf("Thread %d has worked hard and is now terminating\n", idx);
        fflush(stdout);
    
        return NULL ;
    }
    
    int main(int argc, char *argv[]) {
        int s, idx ;
    
        if (argc < 2 || strcmp(argv[1], "--help") == 0) {
            printf("Usage : %s nsecs...\n", argv[0]);
            fflush(stdout);
            exit(-4) ;
        }
        thread = calloc(argc -1, sizeof(*thread) );
        if (thread == NULL) {
            printf("whoops, couldn't allocate memory of size %lu\n", (argc -1) * sizeof(*thread) );
            fflush(stdout);
            exit(-5);
        }
    
        // Let's create all the threads now !!
    
        for (idx =0 ; idx < argc -1 ; idx++ ) {
            thread[idx].sleepTime = atoi(argv[idx + 1 ]) ; // thread sleeps for the duration entered in the cmd line
            thread[idx].state = TS_ALIVE ;
            s = pthread_create(&thread[idx].tid, NULL, threadFunc, &idx);
            printf("Main created thread %d with tid : %lu \n", ( * (int *)&idx ), (unsigned long)thread[idx].tid);
            fflush(stdout);
            if (s != 0 ){
                printf("whoops couldn't create thread %lu\n",(unsigned long) (&thread[idx].tid) );
                fflush(stdout);
                exit(-6) ;
            }
            //sleep(1); // << -- if I don't add this sleep, then it just deadlocks
        }
    
        totThreads = argc -1 ;
        numLive = totThreads ;
    
        // Join terminated threads
    
        while (numLive > 0 ) {
            s = pthread_mutex_lock(&threadMutex) ;
            if (s!=0){
                printf("whoops, couldn't lock mutex for joining\n") ;
                fflush(stdout);
                exit(-7) ;
            }
            while (numUnjoined == 0) {
                s = pthread_cond_wait(&threadDied, &threadMutex) ;
                if (s!=0) {
                    printf("whoops, couldn't wait for thread join\n") ;
                    fflush(stdout);
                    exit(-8) ;
                }
            }
    
            for (idx = 0 ; idx < totThreads ; idx++ ) {
                if (thread[idx].state == TS_TERMINATED) {
                    s = pthread_join(thread[idx].tid, NULL) ;
                    if (s!=0) {
                        printf("Failed thread join\n");
                        fflush(stdout);
                        exit(-9) ;
                    }
    
                    thread[idx].state = TS_JOINED ;
                    numLive-- ;
                    numUnjoined-- ;
                    printf("Reaped thread %d (numLive=%d)\n", idx, numLive);
                    fflush(stdout);
                }
            }
    
            s = pthread_mutex_unlock(&threadMutex) ;
            if (s!=0){
                printf("whopps, couldn't unlock mutex after joining\n");
                fflush(stdout);
                exit(-10) ;
            }
        }
        exit(EXIT_SUCCESS);
    
    }
    

    对于线程数为1的情况,此代码有时可以工作,有时则挂起:(

    工作:

    #./thread\u多连接1

    主创建的线程0,tid为139835063281408

    线程0工作正常,现在正在终止

    收割的线程0(numLive=0)

    挂起:

    #./thread\u多连接1

    主创建的线程0,tid为140301613573888

    线程1工作正常,现在正在终止

    ^C类

    注意这里Main说“线程0已创建”;而线程本身表示“线程1”。。。为什么会出现不匹配??

    当我有多个线程时,它肯定会卡住:

    #./thread\u multijoin 1 2 2 1

    主创建的线程0,tid为140259455936256

    主创建线程1,tid为:140259447543552

    主创建线程2,tid为140259439150848

    主创建线程3,tid:140259430758144

    线程4工作正常,现在正在终止

    线程0工作正常,现在正在终止

    收割螺纹0(numLive=3)

    收割螺纹3(numLive=2)

    线程3工作正常,现在正在终止

    收割螺纹2(numLive=1)

    线程2工作很努力,现在正在终止

    ^C类

    我从中了解到的唯一一件事是,main报告的线程ID与线程本身不同,因此我猜测,由于并行调度,线程计数器出现了一些问题。。。你们能帮我缩小范围吗?

    提前谢谢。

    ========================================

    感谢@mevets和@user3386109的回答:)

    我试着按照@mevets的建议去做:I,e

    pthread\u创建(&thread[idx])。tid,NULL,threadFunc,(void*)idx);

    int idx=(int)arg;

    但在编译时出错:

    thread_multijoin.c: In function ‘threadFunc’:
    
    thread_multijoin.c:32:15: error: cast from pointer to integer of different 
    size [-Werror=pointer-to-int-cast]
    
    int idx = (int)arg  ; // since arg is of type void , we typecast it to * of type int and deref it
    
    
    thread_multijoin.c: In function ‘main’:
    
    thread_multijoin.c:90:64: error: cast to pointer from integer of different 
    size [-Werror=int-to-pointer-cast]
    
    s = pthread_create(&thread[idx].tid, NULL, threadFunc, (void *)idx );
    

    经进一步研究,发现以下线索: cast to pointer from integer of different size, pthread code

    建议使用intptr\t:

    s = pthread_create(&thread[idx].tid, NULL, threadFunc, (void *)(intptr_t)idx );
    

    int idx = (intptr_t)arg
    

    这样做非常好,没有错误。再次感谢您的时间,非常感谢:)

    PS:要使用intptr\u t,您需要使用\u GNU\u源:

    #define _GNU_SOURCE
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   mevets    6 年前

    [线程id]: 您将idx的地址传递给每个线程,然后取消引用以索引表。因此,每个线程都获得相同的指针参数。 您可能想:

            s = pthread_create(&thread[idx].tid, NULL, threadFunc, (void *)idx);
    

    和 int idx=(int)arg;//由于arg是void类型,我们将其类型转换为int类型的*并对其进行deref

    ie;不要删除它,只需在一个空的容器中传递它。