Multi-threaded Text Insertion into a TextView



Hello,

I have several POSIX threads trying to insert text into a Textview. So,
I've used a POSIX mutex to be sure that they are inserting text into the
TextBuffer one after the other.

Most of time, it works but sometimes, I get some GTK error message :

(TTdaq Application v0.8b:16046): Gtk-WARNING **: Invalid text buffer
iterator: either the iterator is uninitialized, or the
characters/pixbufs/widgets in the buffer have been modified since the
iterator was created.
You must use marks, character numbers, or line numbers to preserve a
position across buffer modifications.
You can apply tags and insert marks without invalidating your iterators,
but any mutation that affects 'indexable' buffer contents (contents that
can be referred to by character offset)
will invalidate all outstanding iterators

(TTdaq Application v0.8b:16419): Gtk-CRITICAL **: file gtktextlayout.c:
line 813 (gtk_text_layout_real_invalidate): assertion
`layout->wrap_loop_count == 0' failed

(TTdaq Application v0.8b:18972): Gtk-CRITICAL **: file gtktextlayout.c:
line 813 (gtk_text_layout_real_invalidate): assertion
`layout->wrap_loop_count == 0' failed

(TTdaq Application v0.8b:18510): Gtk-CRITICAL **: file gtktextbuffer.c:
line 1810 (gtk_text_buffer_get_iter_at_mark): assertion
`!gtk_text_mark_get_deleted (mark)' failed

And sometimes... it crashes with a "Segmentation Fault".
I use gtkmm wrapper, but I'm sure you'll guess the gtk functions used.

I have already tried different implementation which doesn't work better
;-) !
One of them was to fill a std::queue and create a Glib thread for
re-read it, and insert the messages into the Textview (a kind of
producer/consummer)... But it crashes even more often !

Here is extracts of my application:

  enum LogType
  {
    INFO,
    WARNING,
    ERROR
  };

  // This function is used by the different threads !
  void add(LogType l, std::string msg)
  {
    pthread_mutex_lock(&pmut_log_update);

    switch(l)
    {
       case INFO:
         globalControlWidget->printInfoLog(msg);
         break;
       case WARNING:
         globalControlWidget->printWarningLog(msg);
         break;
       case ERROR:
         globalControlWidget->printErrorLog(msg);
         break;
    }
    
    pthread_mutex_unlock(&pmut_log_update);  
  }
  
  ....
  /************************************************************/
  // The class GlobalControlWidget
  
  class GlobalControlWidget : public Gtk::VBox
  {
        Gtk::TextView *logText;
        Gtk::ScrolledWindow *logScrolledwindow;
        Glib::RefPtr<Gtk::TextBuffer> refTextLogBuffer;
        Glib::RefPtr<Gtk::TextBuffer::Tag> refTagError;
        Glib::RefPtr<Gtk::TextBuffer::Tag> refTagWarning;
        Glib::RefPtr<Gtk::TextBuffer::TagTable> refTagTable;
        void scrollLogView();
    public:
        GlobalControlWidget(TTdaqMainWindow*);     
        ~GlobalControlWidget();
        void printInfoLog(const std::string &);
        void printErrorLog(const std::string &);
        void printWarningLog(const std::string &);
        void updateStartStopBoutonsSensitivity();
  };


  
  GlobalControlWidget::GlobalControlWidget()
  {
   logText = manage(new class Gtk::TextView());
   logText->set_flags(Gtk::CAN_FOCUS);
   logText->set_editable(false);
   //refTextLogBuffer = Gtk::TextBuffer::create();
   //logText->set_buffer(refTextLogBuffer);
   refTextLogBuffer=logText->get_buffer();

   refTextLogBuffer->signal_changed().connect( sigc::mem_fun(*this,
&GlobalControlWidget::scrollLogView));
 
   //Create a TagTable:
   refTagTable = refTextLogBuffer->get_tag_table();

   //Apply color to some text.
   //Create the tags:
   refTagWarning = Gtk::TextBuffer::Tag::create("Warning_Message"); //We
give it an arbitrary name.
   refTagWarning->property_background() = "orange";
   refTagTable->add(refTagWarning);
   refTagError = Gtk::TextBuffer::Tag::create("Error_Message"); //We
give it an arbitrary name.
   refTagError->property_background() = "red";
   refTagTable->add(refTagError); 
   
   logScrolledwindow = manage(new class Gtk::ScrolledWindow());
   logScrolledwindow->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
   logScrolledwindow->add(*logText);  
   Gtk::Frame *logFrame = manage(new class Gtk::Frame("Log"));
   logFrame->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
   logFrame->set_label_align(0,0);
   logFrame->add(*logScrolledwindow);
   
   pack_start(*logFrame, true, true, 5);
   show_all_children();
   show();
   set_redraw_on_allocate(true);
  }
  
  void GlobalControlWidget::printInfoLog(const std::string &msg)
  {
    refTextLogBuffer->insert(refTextLogBuffer->end(), msg+"\n");
  }

  void GlobalControlWidget::printErrorLog(const std::string &msg)
  {
    refTextLogBuffer->insert_with_tag(refTextLogBuffer->end(), msg+"\n",
refTagError);
  }

  void GlobalControlWidget::printWarningLog(const std::string &msg)
  {
    refTextLogBuffer->insert_with_tag(refTextLogBuffer->end(), msg+"\n",
refTagWarning);
  }

  void GlobalControlWidget::scrollLogView()
  {
    logText->scroll_mark_onscreen( refTextLogBuffer->get_insert() );
  }
  
Pleeaasse heelllpp !!!
Cheers,
DESCOMBES Thierry



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]