【问题标题】:Why does pthread_create() returns 0 but the thread never starts为什么 pthread_create() 返回 0 但线程从不启动
【发布时间】:2018-07-09 06:08:10
【问题描述】:

我来自 Java 背景,并且习惯于使用 Java 的同步进行多线程编程。最近,我开始涉足 C++ 并且不得不处理一些多线程代码。以下是我面临的问题的最小工作示例。

class TxStatus {
    private:
        int numOperations;
        bool commitStatus;
        pthread_mutex_t statusLock;

    public:
        TxStatus() {
            this->commitStatus = false;
            this->numOperations = 0;
        }
        void addNewOperation() {
            pthread_mutex_lock(&statusLock);
            numOperations++;
            pthread_mutex_unlock(&statusLock);
        }
        void operationCompleted() {
            pthread_mutex_lock(&statusLock);
            numOperations--;
            pthread_mutex_unlock(&statusLock);
        }
        void commit() {
            this->commitStatus = true;
        }

};

class TxManager {
    private:
        unsigned long long globalFrontier;
        unsigned long long txId;

        pthread_mutex_t gfLock;
        pthread_mutex_t txIdLock;

        std::map<unsigned long long, TxStatus> txStatusMap;

    public:
        TxManager() {
            pthread_mutex_lock(&gfLock);
            globalFrontier = 1;
            pthread_mutex_unlock(&gfLock);

            pthread_mutex_lock(&txIdLock);
            txId = 1;
            pthread_mutex_unlock(&txIdLock);
        }

        unsigned long long beginNewTx() {
            pthread_mutex_lock(&txIdLock);
            unsigned long long newId = txId;
            txId++;
            pthread_mutex_unlock(&txIdLock);
            TxStatus statusObj;
            txStatusMap.insert(std::make_pair(newId,statusObj));
            return newId;
        }

        void addUnflushedOperation(unsigned long long txId) {
            txStatusMap[txId].addNewOperation();
        }
        void markOperationAsFlushed(unsigned long long txId) {
            txStatusMap[txId].operationCompleted();
        }
        void markCommitted(unsigned long long txId) {
            txStatusMap[txId].commit();
        }
};


void * thread( void *args){

    TxManager txManager;
    fprintf(stderr,"Inside thread");
    unsigned long long newTxId = txManager.beginNewTx();

    fprintf(stderr,"Tx Started: %d", newTxId );
    txManager.addUnflushedOperation(newTxId);
    pthread_exit(NULL);   

}

int main(){
    pthread_t tx_thread;
    fprintf(stderr,"Inside main");
    int ret = pthread_create(&tx_thread, NULL, thread, NULL);
    if (ret != 0)
    {
        fprintf(stderr,"Error launching thread");
    }else{
        fprintf(stderr,"Thread launched successfully");
    }


    if (pthread_join(tx_thread, NULL) != 0)
    {
        fprintf(stderr,"Join pthread failed");
    }

    return 0;

}

线程已成功启动,但我从未看到线程本身执行的函数(即 thread())的打印结果之一。如果我删除了 join 调用,那么程序会在 main 方法中打印语句后终止。

【问题讨论】:

  • 据我所知,您没有初始化互斥锁,您正在锁定不需要锁定的东西,而无法锁定需要锁定的东西。您可以访问C++11std::thread 吗?
  • @Galik 您能否详细说明您所说的“您正在锁定不需要锁定的东西而无法锁定需要锁定的东西”时的意思?
  • 例如,在beginNewTx() 中,您锁定了对txId 的访问,这表明该函数将从多个线程中调用,但您不锁定对txStatusMap 的访问,如果从多个线程修改则需要锁定线程。
  • 另外,在 TxManager 的构造函数中,您在初始化其成员时会锁定访问权限,但不可能有多个线程创建同一个对象,因此您无需锁定对其的访问权限构造函数初始化期间的成员。

标签: c++ pthreads


【解决方案1】:

Pthreads 是一个 C 库。它的数据类型是哑 C 类型。如果您只是将它们放在类或结构中,它们将不会自动初始化。您需要初始化它们。 最简单的方法是使用 PTHREAD_MUTEX_INITIALIZER(或者使用 pthread_mutex_init),在 C++ 中,您可以在成员声明旁边进行。

这不会挂起:

#include <pthread.h>
#include <map>
#include <stdio.h>
using namespace std;
class TxStatus {
    private:
        int numOperations;
        bool commitStatus;
        pthread_mutex_t statusLock = PTHREAD_MUTEX_INITIALIZER;

    public:
        TxStatus() {
            this->commitStatus = false;
            this->numOperations = 0;
        }
        void addNewOperation() {
            pthread_mutex_lock(&statusLock);
            numOperations++;
            pthread_mutex_unlock(&statusLock);
        }
        void operationCompleted() {
            pthread_mutex_lock(&statusLock);
            numOperations--;
            pthread_mutex_unlock(&statusLock);
        }
        void commit() {
            this->commitStatus = true;
        }

};

class TxManager {
    private:
        unsigned long long globalFrontier;
        unsigned long long txId;

        pthread_mutex_t gfLock = PTHREAD_MUTEX_INITIALIZER;
        pthread_mutex_t txIdLock = PTHREAD_MUTEX_INITIALIZER;

        std::map<unsigned long long, TxStatus> txStatusMap;

    public:
        TxManager() {
            pthread_mutex_lock(&gfLock);
            globalFrontier = 1;
            pthread_mutex_unlock(&gfLock);

            pthread_mutex_lock(&txIdLock);
            txId = 1;
            pthread_mutex_unlock(&txIdLock);
        }

        unsigned long long beginNewTx() {
            pthread_mutex_lock(&txIdLock);
            unsigned long long newId = txId;
            txId++;
            pthread_mutex_unlock(&txIdLock);
            TxStatus statusObj;
            txStatusMap.insert(std::make_pair(newId,statusObj));
            return newId;
        }

        void addUnflushedOperation(unsigned long long txId) {
            txStatusMap[txId].addNewOperation();
        }
        void markOperationAsFlushed(unsigned long long txId) {
            txStatusMap[txId].operationCompleted();
        }
        void markCommitted(unsigned long long txId) {
            txStatusMap[txId].commit();
        }
};


void * thread( void *args){

    TxManager txManager;
    fprintf(stderr,"Inside thread\n");
    unsigned long long newTxId = txManager.beginNewTx();

    fprintf(stderr,"Tx Started: %llu", newTxId );
    txManager.addUnflushedOperation(newTxId);
    pthread_exit(NULL);   

}

int main(){
    pthread_t tx_thread;
    fprintf(stderr,"Inside main\n");
    int ret = pthread_create(&tx_thread, NULL, thread, NULL);
    if (ret != 0)
    {
        fprintf(stderr,"Error launching thread");
    }else{
        fprintf(stderr,"Thread launched successfully");
    }


    if (pthread_join(tx_thread, NULL) != 0)
    {
        fprintf(stderr,"Join pthread failed");
    }

    return 0;

}

【讨论】:

    【解决方案2】:

    两件事:

    您的构造函数中似乎缺少对pthread_mutex_init 的调用。这可能是问题的一部分。

    另一个问题是您的 fprintf 语句需要换行。

    也就是这一行:

    fprintf(stderr,"Inside thread");
    

    更新到这个:

    fprintf(stderr,"Inside thread\n");
    

    \n 字符将刷新输出缓冲区,以便您的消息实际出现在屏幕上。

    对其他打印语句应用类似的处理。

    此外,您似乎对每个变量使用了不同的锁。考虑只拥有一个互斥体实例。而且您可能也不需要锁定 TxStatus....

    【讨论】:

      猜你喜欢
      • 2021-01-07
      • 1970-01-01
      • 2020-08-06
      • 2021-01-30
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多