boost wątki

0

Tworze program okienkowy w którym używać będę wątków. Korzystam z biblioteki Boost

oto kod

boost::thread thrd1(&func);   //(1)
thrd1.join();
int func()
        {
	//     
       //
       //
	}

dostaje error w (1) error C2276: '&' : illegal operation on bound member function expression

Te dwa fragmenty kodu zamieszczone sa w tej samej klasie.

0
boost::thread thrd1(boost::bind(&klasa::func,this)); 
0

tez to samo do tego dochodza wtedy bledy zwiazane z rozna iloscia argumentow

0

Nie jestem pewien, ale czy ta funkcja nie musi byc statyczna? (Ewentualnie spróbuj utowrzyc watek dla testow, na jakiejs funkcji globalnej - tu nie potrzeba czynienia ich statystycznymi).

0

Mozna przez klase,

class ServerThread
{
    public:
        QAcceptServerThread(boost::asio::io_service&, std::string&);
        void operator()();

    private:
        boost::asio::io_service& ioS;
        boost::asio::ip::tcp::acceptor* _acceptor;
        boost::asio::ip::tcp::socket* _sock;
        boost::syst....
...
};



ServerThread::ServerThread(boost::asio::io_service& io, std::string &p):ioS(io),port(&p)
{
    using boost::asio::ip::tcp;
    _acceptor = new boost::asio::ip::tcp::acceptor(ioS, tcp::endpoint(tcp::v4(),atoi(port->c_str()) ));
};


void ServerThread::operator()()
{
}
0

No tak, metoda powinna zwracać void, a nie int... nie zauważyłem.

0
0x666 napisał(a)

No tak, metoda powinna zwracać void, a nie int... nie zauważyłem.

To nie ma znaczenia. Wykasuj "&" ze swojego kodu i powinno być Ok (nie sprawdzałem).

0
MarekR22 napisał(a)

Wykasuj "&" ze swojego kodu

wykasowac & przed (kwalifikowana) nazwa metody? zartujesz.. albo uzywasz dziwnego kompilatora. & jest wymagany. nazwa funkcji juz od dawna nie jest identyfikowana ze wskaznikiem-na-funkcje, tymbardziej member..

Rezor napisał(a)

Nie jestem pewien, ale czy ta funkcja nie musi byc statyczna?

tak, metoda musi byc statyczna, stad boost::bind w przykladzie podanym przez 0x666

unknown12 napisał(a)

tez to samo do tego dochodza wtedy bledy zwiazane z rozna iloscia argumentow
masz je gdyz:

0x666 napisał(a)

No tak, metoda powinna zwracać void, a nie int... nie zauważyłem.

zmien typ zwrotu func na void i powinno przejsc. jesli nie - daj caly kod klasy i funkcji w ktorej tworzysz watek

btw. a tu przyklad, jak uzywac boost::thread+boost:
http://aszt.inf.elte.hu/~gsd/klagenfurt/material/ch03s06.html

0

jak zwykle autor watku zapomnial podac najwazniejszej rzeczy..

jakby(ś) raczyl zalaczyc jakis komunikat bledu, tez bysmy Ci od razu odpowiedzieli o co chodzi..

a chodzi o fragmenty kodu:

#pragma once

#include <iostream>
#include "DeviceManager.h"
#include <boost/thread/thread.hpp>

namespace reciver_in_form {

    public ref class Form1 : public System::Windows::Forms::Form
    {
....
        private: System::Void nasluchuj_Click(System::Object^  sender, System::EventArgs^  e) {
.....
            boost::thread thrd(boost::bind(&listenForPacket,this)); 
            thrd.join();
        }

        private: void listenForPacket(){
......
        }
}

...no i wszystko jasne. probujesz operowac na ref-class'ie..

BOOST NIE WSPOLPRACUJE Z C++/CLI
BOOST jest biblioteka C++, nie C++/CLI.
C++/CLI to jeden, a C++ to drugi świat.

nie uda Ci sie takie pomieszanie ani żadne inne podobne, poniewaz NIE MOZNA TRZYMAC REFERENCJI/a tymbardziej jako wartosc/ do obiektow ref- w obiektach ktore ref- nie sa. i kropka. takie jest ograniczenie c++/cli. uznaj ze jest ulomny i tego nie potrafi. bądźmy wdzieczni że przynajmniej potrafi w druga strone...

i z tego powodu, nie mozesz uzyc boost::bind na metodzie z ref-class -- boost::bind probuje zapamietac ptr-na-metode oraz ptr-na-obiekt i to wrecz unmanagedptr-na-obiekt wiec w przypadku gdy podajesz mu ref-class to to sie podwojnie nie ma prawa udac!!

szybki proof:

#pragma once

namespace blah {

    using namespace System;
    using namespace System::Collections;
    using namespace System::Windows::Forms;

    public ref class Form1 : public System::Windows::Forms::Form
    {
    };

    class Test
    {
        Form1^ form;
    };
}

kompilacja:

1>------ Build started: Project: 141243, Configuration: Debug Win32 ------
1>Compiling...
1>main.cpp
1>.\main.cpp(21) : error C3265: cannot declare a managed 'form' in an unmanaged 'reciver_in_form::Test'
1> may not declare a global or static variable, or a member of a native type that refers to objects in the gc heap

1>Build log was saved at "file://c:\poligon\4p\141243\Debug\BuildLog.htm"
1>141243 - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

jesli wiec chcesz uzywac boost::thread, Twoja docelowa metoda do odpalenia musi byc z klasy zwyklej, natywnej, nie-ref.

#pragma once

#include <boost/bind.hpp>
#include <boost/thread.hpp>

namespace blah {

    using namespace System;
    using namespace System::Collections;
    using namespace System::Windows::Forms;

    struct Test
    {
        void threadproc(){}
    };

    public ref class Form1 : public System::Windows::Forms::Form
    {
        void test()
        {
            Test obiekt;  //1

            boost::thread thr(boost::bind(&Test::threadproc, obiekt));
			
            thr.join(); //3
        } //2
    };
}

przyczym, oczywiscie MUSI SIE uwazac na czasy życia obiektow native. obiekt utworzony w (1) rozplynie sie w powietrzu w momencie (2), wiec (3) musi byc przed ta chwila, inaczej watek straci swoj "kontekst".. nie mozesz wiec zaczac w ten sposob watku w metodzie button1_onclick a join w button2_onclick..

szczesliwie klasy ref- potrafia trzymac unmanaged-ptr (ale wartosci juz nie! heh, patrz (*) ), wiec ten problem mozesz rozwiazac prosto np. tak:

#pragma once

#include <boost/bind.hpp>
#include <boost/thread.hpp>

namespace blah {

    using namespace System;
    using namespace System::Collections;
    using namespace System::Windows::Forms;

    struct Test
    {
        void threadproc(){}
    };

    public ref class Form1 : public System::Windows::Forms::Form
    {
        Test* obiekt;    //* - musisz trzymac 'Test*'. proba utworzenia pola typu 'Test' sie nie uda w ref-class.
        boost::thread* thr;

        void test()
        {
            obiekt = new Test();
            thr = new boost::thread(boost::bind(&Test::threadproc, obiekt));
        }

        void detest()
        {
            thr->join();
            delete thr;
            delete obiekt;
        }

        int pole;
        void metoda()
        {
        }
    };
}

oczywiscie, klasa Test kompletnie nieswiadoma istnienia klasy Form, wiec nie da rady wywolac z niej zadnej "metody", ani dostac sie do zadnego pola.
..tak wiec thread proc'a musisz uswiadomic i definicja klasy Form i OBIEKTEM Form..

..tylko jak biedny Test albo Bind sobie przechowa ref do obiektu Form?

jesli wiec operujesz na C++/CLI, przyzwyczaj sie do uzywania CLI i .Net. zapoznaj sie z System.Threading.Thread i uzyj go do opakowywania watkow ktore musza operowac na obiektach ref-class. oszczedzisz sobie bólu głowy..

..o ktory moze kogos przyprawiac takie cos:

#pragma once

#include <string>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

namespace blah {

    using namespace System;
    using namespace System::Collections::Generic;
    using namespace System::Windows::Forms;

    struct Test
    {
        Test(size_t h) : handle(h) {}
        void threadproc();
        size_t handle;
    };

    public ref class Manager
    {
    private:
        static Dictionary<size_t, Object^>^ niechcesztaktegorobic = gcnew Dictionary<size_t, Object^>();

    public:
        static size_t Register(Object^ obj)
        {
            size_t handle = 0; //random.. whatever unique..
            niechcesztaktegorobic->Add(handle, obj);
            //i przydaloby sie reagowac wy-rejestrowaniem na event obj->Disposed, itp..
            return handle;
        }

        template<class T> static T^ Get(size_t handle)
        {
            Object^ obj;
            if(!niechcesztaktegorobic->TryGetValue(handle, obj))
                return nullptr;
            return dynamic_cast<T^>(obj);
        }
    };

    public ref class Form1 : public System::Windows::Forms::Form
    {
        Test* obiekt;
        boost::thread* thr;
        size_t myHandle;

        void test()
        {
            myHandle = Manager::Register(this);
            obiekt = new Test(myHandle);
            thr = new boost::thread(boost::bind(&Test::threadproc, obiekt));
        }

        void detest()
        {
            thr->join();
            delete thr;
            delete obiekt;
            // Manager::Unregister(this, handle);
        }

    public:
        int pole;
        void metoda()
        {
        }
    };

    void Test::threadproc()
    {
        Form1^ ptr = Manager::Get<Form1>(handle);
	
        ptr->pole = 5;
        ptr->metoda();
    }
}
0

Witam,
Zgodnie z tym co mi powiedziałeś używam System::Thread. Właśnie testuje sobie te wątki i od dłuższego czasu zastanawiam się nad jedną rzeczą. Poniższy kod startuje wątek w którym co sekundę powinna być zmieniana własność Visible. Czyli efekt powinien być taki ze widzę w okienku migający napis od label1. Form1 nie odświeża się w tym sensie ze napis nie miga, a button z którego odpalam wątek jest nieaktywny(wciśnięty). Druga sprawa jak odkomentuję kod do drugiego wątku to dostaje wyjątek "thread is running or terminated, cannot restart". Czy ktoś może mi pomóc.
Pozdrawiam

#pragma once

#include "DeviceManager.h"

namespace TestowanieWątków {
		
	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;
	using namespace System::Threading;
	/// <summary>
	/// Summary for Form1
	///
	/// WARNING: If you change the name of this class, you will need to change the
	///          'Resource File Name' property for the managed resource compiler tool
	///          associated with all .resx files this class depends on.  Otherwise,
	///          the designers will not be able to interact properly with localized
	///          resources associated with this form.
	/// </summary>
	public ref class Form1 : public System::Windows::Forms::Form
	{
delegate void FunctionCallback(System::Object ^obj);
		DeviceManager* deviceManager;
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
			deviceManager = new DeviceManager();

		}

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Button^  button1;
	protected: 
	private: System::Windows::Forms::Label^  label1;

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->button1 = (gcnew System::Windows::Forms::Button());
			this->label1 = (gcnew System::Windows::Forms::Label());
			this->SuspendLayout();
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(171, 15);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(108, 92);
			this->button1->TabIndex = 0;
			this->button1->Text = L"button1";
			this->button1->UseVisualStyleBackColor = true;
			this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
			// 
			// label1
			// 
			this->label1->AutoSize = true;
			this->label1->Location = System::Drawing::Point(36, 158);
			this->label1->Name = L"label1";
			this->label1->Size = System::Drawing::Size(35, 13);
			this->label1->TabIndex = 1;
			this->label1->Text = L"label1";
			// 
			// Form1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(292, 266);
			this->Controls->Add(this->label1);
			this->Controls->Add(this->button1);
			this->Name = L"Form1";
			this->Text = L"Form1";
			this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
			this->ResumeLayout(false);
			this->PerformLayout();

		}
#pragma endregion
	private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
			 }
	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {

			Thread^ newThread = gcnew Thread(gcnew ParameterizedThreadStart(&SafeThread4 ));
			newThread->Start(this);
			//Thread^ newThread2 = gcnew Thread(gcnew ParameterizedThreadStart(&SafeThread5));
			//newThread->Start(this);

			 }

static void SafeThread4(System::Object ^obj)
{
     Form1 ^ob = (Form1^) obj;
    if(ob->label1->InvokeRequired)
    {
        FunctionCallback ^d = gcnew FunctionCallback(SafeThread4);
        ob->Invoke(d,gcnew array<System::Object^>{ob});                
    }
    else
    {
        for ( int i = 1; i <= 10; i++ )
        {
			if (i%2==0)
			{
			ob->label1->Visible=false;
            
			}else
			{
				ob->label1->Visible=true;
			}
			Thread::Sleep(1000);
        }

    }
}

/*static void SafeThread5(System::Object ^obj)
{
     Form1 ^ob = (Form1^) obj;
    if(ob->label1->InvokeRequired)
    {
        FunctionCallback ^d = gcnew FunctionCallback(SafeThread4);
        ob->Invoke(d,gcnew array<System::Object^>{ob});                
    }
    else
    {
        for ( int i = 1; i <= 10; i++ )
        {
			if (i%2==0)
			{
			ob->label1->Visible=false;
            
			}else
			{
				ob->label1->Visible=true;
			}
			Thread::Sleep(1000);
        }

    }
}*/

	};
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1