Как найти ошибку (ошибка сегментации) в многопоточной программе C ++ (pthread) в Linux? - PullRequest
5 голосов
/ 29 января 2012

Я делаю отладку для многопоточной программы C ++ (pthread) в Linux.

Хорошо работает, когда номер резьбы мал, например 1, 2,3.

Когда номер потока увеличивается, я получаю SIGSEGV (ошибка сегментации, сигнал UNIX 11).

Но ошибка иногда появляется, а иногда исчезает, когда я увеличиваю число потоков выше 4.

Я использовал Valgrind, я получил

== 29655 == Процесс завершается с действием по умолчанию для сигнала 11 (SIGSEGV)

== 29655 == Доступ не в сопоставленной области по адресу 0xFFFFFFFFFFFFFFF8

== 29655 == в 0x3AEB69CA3E: std :: string :: assign (std :: string const &) (в /usr/lib64/libstdc++.so.6.0.8)

== 29655 == по 0x42A93C: bufferType :: getSenderID (std :: string &) const (boundedBuffer.hpp: 29)

Кажется, мой код пытался прочитать память, которая не выделена. Но я не могу найти никаких ошибок в функции getSenderID (). Он возвращает только строку данных члена в классе bufferType. Это было инициализировано.

Я использовал GDB и DDD (GDB GUI), чтобы найти ошибку, которая также указывает на это, но ошибка иногда исчезает, так что в GDB я не могу захватить ее с точкой останова.

Более того, я также распечатываю значения функции, на которую указывает valgrind, но это бесполезно, потому что несколько потоков выводят результаты в разных порядках, и они чередуются друг с другом. Каждый раз, когда я запускаю код, вывод на печать отличается.

Параметр bufferType находится на карте, карта может иметь несколько записей. Каждая запись может быть записана одним потоком и прочитана другим потоком одновременно. Я использовал блокировку чтения / записи pthread для блокировки pthread_rwlock_t. Теперь нет SIGSEGV, но программа останавливается в какой-то момент без прогресса. Я думаю, что это тупик. Но одна запись на карте может быть записана только одним потоком в один момент времени, почему все еще есть тупик?

Не могли бы вы порекомендовать несколько методов для обнаружения ошибки, чтобы я мог ее найти независимо от того, сколько потоков я использую для запуска кода.

спасибо

Код boundedBuffer.hpp выглядит следующим образом:

 class bufferType
 {
 private:

    string senderID;// who write the buffer

    string recvID; // who should read the buffer

    string arcID; // which arc is updated

    double price; // write node's price 

    double arcValue; // this arc flow value 

    bool   updateFlag ;

    double arcCost;


    int  arcFlowUpBound; 

    //boost::mutex  senderIDMutex; 

    //pthread_mutex_t  senderIDMutex; 

    pthread_rwlock_t       senderIDrwlock;

    pthread_rwlock_t    setUpdateFlaglock;

  public: 
   //typedef boost::mutex::scoped_lock lock;  // synchronous read / write 

   bufferType(){}

   void   getPrice(double& myPrice ) const {myPrice = price;}

   void   getArcValue(double& myArcValue ) const {myArcValue = arcValue;}

   void   setPrice(double& myPrice){price = myPrice;}

   void   setArcValue(double& myValue ){arcValue = myValue;}

   void   readBuffer(double& myPrice, double& myArcValue );

   void   writeBuffer(double& myPrice, double& myArcValue );

   void   getSenderID(string& myID) 

   {
       //boost::mutex::scoped_lock lock(senderIDMutex);
      //pthread_rwlock_rdlock(&senderIDrwlock); 
      cout << "senderID is " << senderID << endl ; 
      myID = senderID;
      //pthread_rwlock_unlock(&senderIDrwlock);
   }
//void   setSenderID(string& myID){ senderID = myID ;}

    void   setSenderID(string& myID)

    { 
        pthread_rwlock_wrlock(&senderIDrwlock); 

            senderID = myID ;

            pthread_rwlock_unlock(&senderIDrwlock);
    }

    void   getRecvID(string& myID) const {myID = recvID;}

    void   setRecvID(string& myID){ recvID = myID ;}

    void   getArcID(string& myID) const {myID  = arcID ;}

    void   setArcID(string& myID){arcID = myID ;}

    void   getUpdateFlag(bool& myFlag)
    {
            myFlag = updateFlag ; 

        if (updateFlag)

           updateFlag  = false; 
    }

//void   setUpdateFlag(bool myFlag){ updateFlag = myFlag ;}

    void   setUpdateFlag(bool myFlag)
    { 
        pthread_rwlock_wrlock(&setUpdateFlaglock);

        updateFlag = myFlag ;

         pthread_rwlock_unlock(&setUpdateFlaglock);

    }

   void   getArcCost(double& myc) const {myc = arcCost; }

   void   setArcCost(double& myc){ arcCost = myc ;}

   void   setArcFlowUpBound(int& myu){ arcFlowUpBound = myu ;}

   int    getArcFlowUpBound(){ return arcFlowUpBound ;}

   //double getLastPrice() const {return price; }

   } ;

Из кода видно, что я пытался использовать блокировку чтения / записи для обеспечения инварианта. Каждая запись в карте имеет буфер, подобный приведенному выше. Теперь у меня тупик.

Ответы [ 3 ]

4 голосов
/ 29 января 2012

Access not within mapped region at address 0xFFFFFFFFFFFFFFF8

at 0x3AEB69CA3E: std::string::assign(std::string const&)

Обычно это означает, что вы присваиваете значение string*, равное NULL, а затем уменьшается,Пример:

#include <string>

int main()
{
  std::string *s = NULL;

  --s;
  s->assign("abc");
}

g++ -g t.cc && valgrind -q ./a.out

...
==20980== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==20980==  Access not within mapped region at address 0xFFFFFFFFFFFFFFF8
==20980==    at 0x4EDCBE6: std::string::assign(char const*, unsigned long)
==20980==    by 0x400659: main (/tmp/t.cc:8)

...

Итак, покажите нам код в boundedBuffer.hpp (с номерами строк), и подумайте , как этот код может закончитьсястроковый указатель, который указывает на -8.

Не могли бы вы порекомендовать несколько методов для выявления ошибки, чтобы я мог ее найти независимо от того, сколько потоков я использую для запуска кода.

Когда вы думаете о многопоточных программах, вы должны думать об инвариантах.Вы должны поставить утверждения, чтобы подтвердить, что ваши инварианты сохраняются.Вы должны подумать , как они могут быть нарушены, и какие нарушения могут привести к посмертному состоянию, которое вы наблюдали.

2 голосов
/ 29 января 2012

Есть ли у вас случаи, когда объект (такой как строка) доступен в одном потоке, в то время как другой поток изменяет или может изменить его?Это обычная причина такой проблемы.

0 голосов
/ 29 января 2012

Посмотрите на ваш экземпляр bufferType.

Когда он был создан?

Если он был создан до появления потоков, а затем один из потоков изменил его, у вас есть состояние гонки без блокировки.

Кроме того, следите за любыми статическими переменными где-нибудь рядом или внутри этого bufferType.

Судя по всему, одиниз потоков, вероятно, изменил член, который был возвращен getSenderID ().

Если ни одна из этих проблем не вызывает вашу ошибку, попробуйте использовать drg * valgrind .

...