سؤال

أريد أن أقوم بهذا العمل البسيط من التعليمات البرمجية.

#include <iostream>
#include <windows.h>


    void printSome (int i)
    {
        std::cout << i << std::endl;
    }

    void spawnThread (void (*threadName)(int i))
    {
        CreateThread 
            (
                0,      // default security attributes
                0,          // use default stack size 
                (LPTHREAD_START_ROUTINE)threadName,  // thread function name
                (LPVOID)i,          // argument to thread function 
                0,          // use default creation flags 
                0       // returns the thread identifier 
            );  
    }

    int main ()
    {
        spawnThread(printSome(155));
    }

أنا على ويندوز، وذلك باستخدام مقابل.سيتم تقدير أي مساعدة إلى حد كبير.

هل كانت مفيدة؟

المحلول

وأنا شخصيا لن تنظر في تمرير مؤشر دالة وكأنك تحاول أن تفعل كما جدا C ++ مثل. هذا الترميز C ++ C في

وبدلا من ذلك، فما استقاموا لكم فاستقيموا التفاف هذا الشيء في فئة. ميزة كبيرة هناك يمكنك فقط تجاوز فئة لديها ولكن العديد من أعضاء تريدها، بدلا من الاضطرار إلى أداء الحيل الصب greazy للحصول على المعلمات في كل مرة.

والمدونة ينضب طويلة قليلا، حتى لقد ضغطت عليه حتى النهاية. ولكن ما يتيح لك القيام به هو شيء من هذا القبيل:

   class print_some : public basic_thread {
    private:
       int i;
    public:     
       print_some (int i) : i(i) {};
       action_callback () {
          std::cout << i << std::endl;
       }
    }
    int main () {
       print_some printer (155);
    }

وإليك بعض exerpted المثال رمز من أحد صفوفنا أن يفعل هذا:

class basic_thread : 
{
public:
   basic_thread();
protected:
   unsigned long m_ThreadId;

   virtual void action_callback () {};

   // Internal routine used to bridge between OS callback format and 
   // action_callback. *Must* be static for the OS.
   static unsigned long __stdcall self_calling_callback (void *parameter);
}

... وفي .CPP:

unsigned long __stdcall basic_thread::self_calling_callback (void *parameter) {
   if (parameter) {
      basic_thread * thread = reinterpret_cast<basic_thread *>(parameter);
      thread->action_callback();
   }
   return 0; // The value returned only matters if someone starts calling GetExitCodeThread
             // to retrieve it.
}

basic_thread::basic_thread () {
   // Start thread.
   m_Handle = CreateThread(NULL,
                           0,
                           self_calling_callback,
                           (PVOID)this,
                           0,
                           &m_ThreadId );
   if( !IsHandleValid() )
      throw StartException("CreateThread() failed", GetLastError());

}

نصائح أخرى

وCreateThread يريد 2 الحجج: مؤشر إلى وظيفة لتنفيذ بأنه موضوع، وحجة DWORD التي من شأنها أن تعطى للموضوع. الدالة spawnThread () و 1 الحجة (threadName) فقط؛ لك <م> التفكير لها 2 وسائط بسبب "أنا"، ولكن هذا هو في الحقيقة جزء من تعريف "threadName" نوع. (هل يمكن أن مجرد ترك فضلا من "أنا"؛ وهذا هو، لا تحتاج إلى تسمية الوسائط إلى "threadName")

وعلى أي حال، بالنظر إلى أن تحتاج 2 الحجج، وإعادة تعريف spawnThread:

   void spawnThread(void (*threadEntryPoint)(int), int argument)
   {
      CreateThread(0,0,
                   (LPTHREAD_START_ROUTINE)threadEntryPoint,
                   (LPVOID)argument,
                   0,0);
   }

لاحظ أن لم أكن <م> الاسم حجة الباحث إلى threadEntryPoint. يكفي أن نقول للمترجم التي يجب أن يكون وظيفة حجة كثافة واحدة.

ووالذي يطلق عليه:

   spawnThread(printSome, 155);

وعلى أي حال، سريعة وقذرة، وهذا سوف تفعل ما تريد.

وهته.

ورايلي.

وأنت لا يمكن تمرير معلومات معلمة في مؤشر دالة. يجب تمريرها بشكل منفصل. هذا هو بالضبط لماذا توفر وظيفة CreateThread فراغا * المعلمة التي يمكن أن نشير إلى ما تريد.

وبالإضافة إلى ذلك، يجب عليك استخدام _beginthread بدلا من CreateThread لتطبيقات C ++.

وأخيرا، البرنامج الخاص بك هو أكثر من المحتمل أن ينهي قبل تشغيل موضوع من أي وقت مضى. ولذلك، يجب عليك إما إدخال حلقة غير محددة أو استخدام مكالمة API إلى الانتظار لمؤشر الترابط لإنهاء.

وفيما يلي نسخة تعمل باستخدام WaitForSingleObject لمنع حتى يكمل الموضوع.

#include <iostream>
#include <process.h>
#include <windows.h>

void
printSome(int i)
{
    std::cout << i << std::endl;
}

HANDLE
spawnThread(void (*threadName)(int), int i)
{
    return (HANDLE) _beginthread((void (*)(void*)) threadName, 0, (LPVOID) i);      
}

int
main(int argc, char *argv[])
{
    HANDLE threadHandle;

    threadHandle = spawnThread(printSome, 155);
    WaitForSingleObject(threadHandle, INFINITE);

    return 0;
}

وهنا هو C ++ / الطريق أكثر من ذلك بكثير وجوه المنحى على التعامل مع هذا الوضع نفسه:

#include <iostream>
#include <process.h>
#include <windows.h>

class Thread {
    static void proxy(void *arg) { (*(reinterpret_cast<Thread *> (arg)))(); }
    HANDLE thread_;

public:
    virtual ~Thread() {}
    virtual void operator()() = 0;  
    void start() { thread_ = (HANDLE) _beginthread(Thread::proxy, 0, this);}    
    void waitForExit() { WaitForSingleObject(thread_, INFINITE); }
};

class Printer : public Thread {
    int i_;

public:
    Printer(int i) : i_(i) {}
    void operator()() { std::cout << i_ << std::endl; }
};

int
main(int argc, char *argv[])
{
    Printer p(155);

    p.start();
    p.waitForExit();

    return 0;
}

كما ذكر العديد من الأشخاص هنا، لا يمكنك تمرير مؤشر دالة والوسيطة التي يجب استدعاؤها باستخدام معلمة واحدة.

خطك

    spawnThread(printSome(155));

تعني كلمة "should" (في عالم DWIM) "استدعاء printSome في سلسلة رسائل منفصلة باستخدام الوسيطة 155".ومع ذلك، ليس هذا هو ما يفهمه C++.يرى C++ "تمرير نتيجة استدعاء printSome على 155 كمعلمة لـ SpawnThread".بمعنى آخر، تسلسل الخطوات هو:

  • استدعاء prinotSome مع 155 كوسيطة.تخزينها في الذاكرة المؤقتة.
  • استدعاء SpawnThread مع محتويات الذاكرة المؤقتة كوسيطة لها.

لكي تفعل ما تقصده حقًا، عليك أن تقوم بفكاهة لغة C++ وفصل الوسيطة عن الوظيفة.تم شرح كيفية القيام بذلك بالفعل في الإجابات الأخرى.واختصارها هو:

callOnOtherThreadWithArgument(function, integer);

ويمكنك أن تقرأ كيف يمكنك أن تفعل ذلك هنا: http://www.newty.de/ FPT / fpt.html

<اقتباس فقرة>   

2.6 كيفية تمرير مؤشر دالة ك وسيطة؟

     

ويمكنك تمرير مؤشر دالة على أنها   حجة يدعو الدالة. انت تحتاج   هذا على سبيل المثال إذا كنت تريد تمرير   مؤشر دالة رد. ال   يظهر التعليمة البرمجية التالية كيفية تمرير   مؤشر دالة التي تقوم بإرجاع   int و يأخذ تعويم واثنين من شار:

//------------------------------------------------------------------------------------
// 2.6 How to Pass a Function Pointer

// <pt2Func> is a pointer to a function which returns an int and takes a float and two char
void PassPtr(int (*pt2Func)(float, char, char))
{
   int result = (*pt2Func)(12, 'a', 'b');     // call using function pointer
   cout << result << endl;
}

// execute example code - 'DoIt' is a suitable function like defined above in 2.1-4
void Pass_A_Function_Pointer()
{
   cout << endl << "Executing 'Pass_A_Function_Pointer'" << endl;
   PassPtr(&DoIt);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top