Windows iş parçacığı: _beginthread, _beginthreadex ve CreateThread C ++


133

Bir iş parçacığı başlatmanın daha iyi bir yolu nedir _beginthread, _beginthreadxveya CreateThread?

Ben avantajları / dezavantajları nelerdir belirlemeye çalışıyorum _beginthread, _beginthreadexve CreateThread. Tüm bu işlevler yeni oluşturulan bir iş parçacığına bir iş parçacığı tutamacı döndürür, CreateThread'in bir hata oluştuğunda biraz daha fazla bilgi sağladığını zaten biliyorum (arayarak kontrol edilebilir GetLastError) ... ama ne zaman düşünmem gereken şeyler nelerdir? Bu işlevleri kullanıyorum?

Bir Windows uygulamasıyla çalışıyorum, bu nedenle platformlar arası uyumluluk zaten söz konusu değil.

Msdn belgelerini inceledim ve örneğin neden herhangi birinin CreateThread yerine _beginthread kullanmaya karar verdiğini veya bunun tersini anlayamıyorum.

Şerefe!

Güncelleme: Bütün bilgi için Tamam, teşekkürler Ben de arayamayacağımı yerlerde birkaç okudum WaitForSingleObject()ben kullanılırsa _beginthread(), ama ararsanız _endthread()iplik değil işin o ki? Orada anlaşma nedir?


2
İşte C / C ++ programcıları için _beginthreadex dair bir analiz () yapar Eli Bendersky internet sitesinde bir bağlantıdan bulduğunu söyledi. Bu, CreateThread () kullanılıp kullanılmayacağına ilişkin bir Soru-Cevaptan alınmıştır. microsoft.com/msj/0799/win32/win320799.aspx
Richard Chambers

Yanıtlar:


96

CreateThread() çekirdek düzeyinde başka bir kontrol dizisi oluşturmak için ham bir Win32 API çağrısıdır.

_beginthread()& perde arkasını _beginthreadex()çağıran C çalışma zamanı kitaplığı çağrılarıdır CreateThread(). Döndüğünde CreateThread(),_beginthread/ex() C çalışma zamanı kitaplığını yeni iş parçacığında kullanılabilir ve tutarlı hale getirmek için ek defter tutma ile ilgilenir.

C ++ ' _beginthreadex()da, C çalışma zamanı kitaplığına hiç bağlanmayacaksanız (diğer adıyla MSVCRT * .dll / .lib) neredeyse kesinlikle kullanmalısınız .


39
Bu artık eskisi kadar doğru değil. CRT, sinyal () işlevi dışında CreateThread () tarafından oluşturulan bir evrede doğru şekilde çalışacaktır. CRT kullanan CreateThread () ile oluşturulan her iş parçacığı için küçük bir bellek sızıntısı (~ 80 bayt) olacak, ancak doğru şekilde çalışacaktır. Daha fazla bilgi için bakın: support.microsoft.com/default.aspx/kb/104641
John Dibling

1
@John: Aslında bu hata MSVC ++ 6.0'a
bobobobo

5
@bobobobo: Güzel soru. Sadece MS'nin başlangıçta _beginrutinleri dahili aramalar olarak tasarladığını ve CreateThreadherkesin arayacağı API işlevi olması gerektiğini tahmin edebilirim. Diğer bir olası açıklama da MS'nin standardı görmezden gelme ve şeyleri adlandırmak konusunda çok kötü kararlar verme konusunda uzun ve şanlı bir geçmişe sahip olmasıdır.
John Dibling

15
_beginFonksiyonları bir alt çizgi ile başlar , çünkü Microsoft daha yakından standardını takip etmeye başladı. C çalışma zamanında, alt çizgiye sahip olan adlar uygulama için ayrılmıştır (ve uygulama, bunlarda olduğu gibi son kullanıcı kullanımı için bunları belgeleyebilir). beginthreadex()kullanıcının kullanmasına izin verilen bir isimdir. C çalışma zamanı onu kullandıysa, kullanıcının kullanmayı beklemek için meşru hakka sahip olduğu bir son kullanıcı simgesiyle çakışabilir. Win32 API'lerinin C çalışma zamanının bir parçası olmadığını ve kullanıcının ad alanını kullandıklarını unutmayın.
Michael Burr

2
@Lothar: Orada olan Win32 API çağrısı arasındaki farklar CreateThreadve CRT aramaları _beginthread/exve iş parçacığı üzerinde CRT çağrılırken, her zaman birlikte oluşturulmalıdır _beginthread/ex. Yapmazsanız, artık bellek sızıntısı olmayabilir. Ancak CreateThread, örneğin arama sırasında kayan nokta ortamınızı kesinlikle düzgün bir şekilde başlatamayacaksınız . Orada daha : "Bir iplik kullanılarak oluşturulan Eğer CreateThread CRT çağırır CRT düşük bellek koşullarında süreci sona erdirebilir."
IInspectable

37

Arasında birçok fark vardır _beginthread()ve _beginthreadex(). (hem parametrelerde hem de nasıl davrandığında) _beginthreadex()daha çok davranması için yapılmıştır CreateThread().

Gibi Drew Hall bahseder C / C ++ çalışma zamanını kullanıyorsanız, kullanmanız gerekir _beginthread()/ _beginthreadex()yerine CreateThread()çalışma zamanı (vb parçacığı yerel depolama kurma) kendi iplik başlatma var gerçekleştirmek için bir şansı var ki.

Pratikte bu CreateThread(), kodunuz tarafından hemen hemen hiçbir zaman doğrudan kullanılmaması gerektiği anlamına gelir .

Farklılıklar için MSDN belgeleri _beginthread()/ _beginthreadex()oldukça fazla ayrıntıya sahiptir - daha önemli olanlardan biri _beginthread(), iş parçacığı çıkarken CRT tarafından oluşturulan bir iş parçacığı için iş parçacığı tutamacının otomatik olarak kapanmasıdır, "_beginthread tarafından oluşturulan iş parçacığı çıkarsa çabucak, _beginthread çağırana dönen tutamaç geçersiz olabilir veya daha kötüsü başka bir iş parçacığına işaret edebilir ".

İşte _beginthreadex()CRT kaynağındaki yorumların söylemesi gerekenler :

Differences between _beginthread/_endthread and the "ex" versions:

1)  _beginthreadex takes the 3 extra parameters to CreateThread
  which are lacking in _beginthread():
    A) security descriptor for the new thread
    B) initial thread state (running/asleep)
    C) pointer to return ID of newly created thread

2)  The routine passed to _beginthread() must be __cdecl and has
  no return code, but the routine passed to _beginthreadex()
  must be __stdcall and returns a thread exit code.  _endthread
  likewise takes no parameter and calls ExitThread() with a
  parameter of zero, but _endthreadex() takes a parameter as
  thread exit code.

3)  _endthread implicitly closes the handle to the thread, but
  _endthreadex does not!

4)  _beginthread returns -1 for failure, _beginthreadex returns
  0 for failure (just like CreateThread).

Ocak 2013 güncellemesi :

VS 2012 için CRT'nin içinde gerçekleştirilen ek bir başlatma biti vardır _beginthreadex(): eğer işlem bir "paketlenmiş uygulama" ise (eğer yararlı bir şey döndürülürse GetCurrentPackageId()), çalışma zamanı yeni oluşturulan iş parçacığı üzerinde MTA'yı başlatacaktır.


3
Orada olan CreateThread () garanti edilir uygun kez, ama dürüstçe gerçekten bunu yapmak için yol dışına gitmek zorunda. Taşınabilir herhangi bir şeyin eksikliğinden bahsediyoruz ve yalnızca bir WIN32 API DLL veya Uygulaması yazıyoruz. Hiçbir C çalışma zamanı çağrısı dahil değildir. STL kullanımı bile, WIN32 bellek yönetimi işlevlerini kullanmak için özel ayırıcılar sağlamanız gerektiğinden sınırlıdır. Bunu Developer Studio ile yapmak için kurulum başlı başına bir iştir, ancak mümkün olan en küçük ayak izine sahip tek bir WIN32 kitaplığı için bu yapılabilir. Ama evet, seçkin bir azınlık dışında neredeyse hepsi için kanlı bir olasılık değil.
WhozCraig

1
@WhozCraig: CRT'yi atlarken daha ciddi sınırlamalar vardır. En önemlileri şunlardır: 64-bit tam sayı desteği yok, kayan nokta desteği yok ve - en önemlisi - istisna işleme yok. Bu gerçekten istisnai bir işlem olmadığı anlamına gelir - hiç . SEH istisnaları bile yok. Bunu telafi etmek özellikle zordur CreateThreadve Doğru Şey olma çağrısı yapma şansı giderek azalıyor.
2014

@MichaelBurr: VC ++ 2015 için cevabınızı güncellemek isteyebilirsiniz .
user541686

@Mehrdad: Hangi değişiklikleri özellikle belirtmeye değer buluyorsunuz?
IInspectable

DisableThreadLibraryCalls'ın CreateThread ile oluşturulan iş parçacıkları üzerinde hiçbir etkisi olmadığını, ancak _beginthread veya _beginthreadex ile oluşturulan iş parçacıklarını devre dışı bıraktığını buldum.
SPlatten

23

Genel olarak, yapılacak doğru şey aramaktır _beginthread()/_endthread()(veya ex()varyantları). Bir .dll CRT kullanmak Ancak, CRT devlet düzgün başlatılmış ve CRT en olarak yok edilecek DllMainolan adı verilecek DLL_THREAD_ATTACHve DLL_THREAD_DETACHçağrılırken CreateThread()ve ExitThread()ya sırasıyla dönüyor.

DllMainCRT için kod \ crt \ src \ crtlib.c VC altında VS için yüklemek dizinde bulunabilir.


Harika bir başlangıç ​​noktası. Küçük bir hata ayıklama ile __CRTDLL_INIT'in durağan bağlantılı bir CRT için bile çağrıldığını gösterebilir. İnit çağrısı _LdrpCallInitRoutine @ 16 (), tam olarak hangi mekanizma tarafından emin değilim. Bu, son CRT ile tüm başlatma / yeniden başlatma işlemlerinin, sinyal işleme haricinde doğru şekilde yapıldığı anlamına gelir; bu, yine de beginthread'den çağrılan _threadstartex yardımcı işlevinde yapılır, ancak CreateThread'den yapılmaz. Belki bunu cevaba eklersiniz ve ödülü ben veririm?
Suma

En yararlı göründüğü için ödül verildi. Yine de cevap belki de güncellenmeye değer olabilir. Eğer yapamazsan, birkaç gün içinde tekrar ziyaret edebilirim.
Suma

1
@MSN: Statik CRT agains bağlantı veriyorsa CreateThread bir DLL hala kötü olduğunu, lütfen unutmayın ve DLL_THREAD_DETACH çağrılarını devre dışı bırakır DisableThreadLibraryCalls çağrıda bulundular. Sonra bellek sızıntıları yaşarsınız. Bu, şu KB makalemde belgelenmiştir: support.microsoft.com/kb/555563/en-us
Jochen Kalmbach

17

Bu, özündeki koddur _beginthreadex(bakınız crt\src\threadex.c):

    /*
     * Create the new thread using the parameters supplied by the caller.
     */
    if ( (thdl = (uintptr_t)
          CreateThread( (LPSECURITY_ATTRIBUTES)security,
                        stacksize,
                        _threadstartex,
                        (LPVOID)ptd,
                        createflag,
                        (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
    {
            err = GetLastError();
            goto error_return;
    }

Geri kalanı _beginthreadexCRT için iş parçacığı başına veri yapısını başlatır.

Kullanmanın avantajı, _beginthread*iş parçacığından gelen CRT çağrılarınızın doğru şekilde çalışmasıdır.


12

C çalışma zamanı kitaplığının iş parçacığının kendi başlatmasını yapmasına izin vermek için _beginthreadveya kullanmalısınız _beginthreadex. Artık kendi geliştirme ortamlarını kullanma kurallarını bilmeleri gerektiğinden, yalnızca C / C ++ programcılarının bunu bilmesi gerekir.

Eğer kullanırsanız , RTL sizin için yapacağı için _beginthreadaramanıza gerek CloseHandleyoktur. Bu yüzden kullandıysanız tutamağı bekleyemezsiniz _beginthread. Ayrıca _beginthread, başlatma iş parçacığı, henüz başlattığı iş parçacığı için geçersiz bir iş parçacığı tutamacı tutarken bırakıldığında, iş parçacığı işlevi hemen (hızlı) çıkarsa kafa karışıklığına yol açar.

_beginthreadextutamaçlar beklemek için kullanılabilir, ancak aynı zamanda açık bir çağrı gerektirir CloseHandle. Bu, onları beklemek için güvenli kılan şeyin bir parçasıdır. Tamamen kusursuz hale getirmenin başka bir sorunu da, iş parçacığını her zaman askıda başlatmaktır. Başarı, kayıt tutacağı vb. Olup olmadığını kontrol edin. Bu, başlatılan iş parçacığının tanıtıcısını kaydetmeden önce bir iş parçacığının sona ermesini önlemek için gereklidir.

En iyi uygulama, kullanmak _beginthreadex, askıya almak ve kayıt tutamacından sonra devam etmektir, tutamaca beklemek tamam ise CloseHandleçağrılmalıdır.


8

CreateThread()kodunuzda herhangi bir CRT işlevi kullandığınızda bellek sızıntısı oluyordu. _beginthreadex()ile aynı parametrelere sahiptir CreateThread()ve daha çok yönlüdür _beginthread(). Bu yüzden kullanmanızı tavsiye ederim _beginthreadex().


2
1999 makalesi, o zamandan beri düzeltilmiş olabilir
bobobobo

1
2005 tarihli bu makale hala bir sorun olduğunu doğrulamaktadır.
Jaywalker

2
Evet, yalnızca MSVC ++ 6.0 Service Pack 5 ve öncesi için geçerlidir. ("Şunlar için geçerlidir" genişletilebilir açılır menüsüne bakın). VC7 veya üstünü kullanıyorsanız bugün bu bir sorun değildir.
bobobobo

1
Statik CRT'yi tekrar bağlarsanız, bu hala bir sorundur! Ayrıca, statik olarak bağlı bir DLL'de DisableThreadLibraryCalls'ı çağırırsanız, yine de bir sorundur; KB
makaleme

2
Bilgiyi yanlış: CreateThreadyok hiç değil bellek sızdırıyor. Daha çok, düzgün şekilde başlatılmamış bir iş parçacığından çağrıldığında yapan CRT'dir.
IInspectable

6

"Ben de arayamayacağımı yerlerde birkaç okudum: güncellenmiş soru ile ilgili olarak WaitForSingleObject()kullandığım takdirde _beginthread(), ama ararsanız _endthread()dizisindeki olmamalı işin bu mu?"

Genel olarak, WaitForSingleObject()iş parçacığı tamamlanana kadar engellemek için bir iş parçacığı tanıtıcısına (veya nesne tanıtıcılarında bekleyen diğer API'lere) iletebilirsiniz . Ancak, tarafından oluşturulan iş parçacığı tanıtıcısı çağrıldığında _beginthread()kapalıdır _endthread()(bu açıkça yapılabilir veya iş parçacığı yordamı döndüğünde çalışma zamanı tarafından örtük olarak yapılabilir).

Sorun aşağıdakiler için dokümantasyonda belirtilmiştir WaitForSingleObject():

Bekleme hala beklemedeyken bu tutamaç kapatılırsa, işlevin davranışı tanımsızdır.


5

İşlev imzalarına bakmak CreateThreadile neredeyse aynıdır _beginthreadex.

_beginthread,_beginthreadx vsCreateThread

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

uintptr_t _beginthread( 
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
);

uintptr_t _beginthreadex( 
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
);

Üzerinde açıklamalar burada söylemek _beginthreadbirini kullanabilirsiniz __cdeclveya __clrcallbaşlangıç noktası olarak çağırma ve _beginthreadexkullanabilirsiniz __stdcallveya __clrcallbaşlangıç noktası için.

İnsanların bellek sızıntıları üzerine yaptığı yorumların CreateThreadon yıldan daha eski olduğunu ve muhtemelen göz ardı edilmesi gerektiğini düşünüyorum.

İlginç bir şekilde, her iki _beginthread*işlev de makinemde CreateThreadkaputun altını çağırıyor C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src.

// From ~line 180 of beginthreadex.c
/*
 * Create the new thread using the parameters supplied by the caller.
 */
if ( (thdl = (uintptr_t)
      CreateThread( (LPSECURITY_ATTRIBUTES)security,
                    stacksize,
                    _threadstartex,
                    (LPVOID)ptd,
                    createflag,
                    (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
{
        err = GetLastError();
        goto error_return;
}


3

beginthreadexve arkadaşlarınızda HANDLEkullanmanız için size bir ileti dizisi verir WaitForSingleObject. beginthreadyapmaz. İşin CloseHandle()bittiğinde unutma . Gerçek cevap boost::threadC ++ 09'un iş parçacığı sınıfını kullanmak veya yakında kullanmak olacaktır .


Msdn açıklaması "Başarılı olursa, bu işlevlerin her biri yeni oluşturulan iş parçacığı için bir tutamaç döndürür" der; _beginthread () ve _beginthreadex () ile ilgili ...
Kiril

@Kiril: ama sonra dokümantasyon, _beginthread'in sizin için tanıtıcıyı kapattığını söylüyor, yani iş parçacığı hızlı bir şekilde çıkarsa onu kullanamazsınız ...
Roger Lipscombe

2

Karşılaştırıldığında _beginthreadile, _beginthreadexşunları yapabilirsiniz:

  1. Güvenlik özniteliklerini belirtin.
  2. Askıya alınmış durumda bir ileti dizisi başlatın.
  3. Kullanılabilecek iş parçacığı kimliğini alabilirsiniz OpenThread.
  4. Çağrının başarılı olması durumunda, döndürülen iş parçacığı tutamacının geçerli olması garanti edilir. Kolu ile kapatmanız gerekiyor CloseHandle.
  5. Döndürülen iş parçacığı tanıtıcısı, senkronizasyon API'leri ile kullanılabilir.

_beginthreadexYakından benzeyen CreateThread, fakat eski bir CRT uygulanması ve ikincisi, bir Windows API çağrıdır. CreateThread belgeleri aşağıdaki önerileri içerir:

C çalışma zamanı kitaplığını (CRT) çağıran yürütülebilir bir iş parçacığı, iş parçacığı yönetimi için ve yerine _beginthreadexve _endthreadexişlevlerini kullanmalıdır ; bu, CRT'nin çok iş parçacıklı sürümünün kullanılmasını gerektirir. CRT kullanılarak oluşturulan bir iş parçacığı çağrılırsa, CRT işlemi düşük bellek koşullarında sonlandırabilir.CreateThreadExitThreadCreateThread


API spesifikasyonuna göre, madde işaretleri 3-5'e özgü değildir _beginthreadex. Her uintptr_tiki işlevden de dönüşü HANDLE.
Andon M. Coleman

Evet, teoride haklısınız. Uygulamada, fark, _beginthreadçıkışta kolu kapatmasıdır. Dolayısıyla, tutamacı eşitlemek ve çoğaltmak için başka bir yol kullanana kadar eşzamanlama API'leriyle iş parçacığını güvenilir bir şekilde kullanamazsınız veya iş parçacığı kimliğini elde edemezsiniz. Ama sonra _beginthreadexbunu sizin için yapıyor.
Vishal

2

CreateThread()CRT yanlış bir şekilde başlatılacağı / temizleneceği için bir kez hayır-hayırdı. Ancak bu artık tarih oldu: CRT'yi bozmadan artık (VS2010 ve muhtemelen birkaç sürüm geri kullanılarak) arama yapılabilir CreateThread().

İşte resmi MS onayı . Bir istisna belirtir:

Aslında ile oluşturulan dizisindeki kullanılmamalıdır tek işlevi CreateThread()olan signal()işlevi.

Ancak tutarlılık açısından kişisel olarak kullanmaya devam etmeyi tercih ediyorum _beginthreadex().


Bunun doğru olduğunu düşünmeme rağmen, MS Belgelerine bağlanarak veya CRT _beginthreadex / _endthreadex kaynaklarını analiz ederek bazı güvenilir kanıtlar sağlayabilir misiniz?
Suma

@Suma, sanırım MS bağlantısını siz yorumunuzu yazarken
ekledim

Bağlandığınız belge doğrulamıyor gibi görünüyor: "Ancak, hangi CRT işlevlerinin adlandırıldığına bağlı olarak, iş parçacıkları sonlandırıldığında küçük bir bellek sızıntısı olabilir." Bu, artık büyük ve genel bir hayır değil, ancak sık sık iş parçacığı oluşturuyorsanız ve bu işlevleri içlerinde kullanıyorsanız yine de hayır-hayır anlamına gelir. Ancak belge 2005 yılına aittir ve bu nedenle konunun son durumuna değinemez.
Suma

1
Hmm ... kullanım durumuna bağlı olsa da, bellek sızıntısı bırakan bir işlev, hangi boyutta olursa olsun, hayır-hayır diye düşünürdüm - özellikle sızdırmayan bir alternatif varsa!
alk

"CRT'yi bozmadan artık CreateThread () çağrılabilir." - Ne yazık ki bu doğru değil ve asla da olmadı. Gönderen CreateThread : Bir iş parçacığı CreateThread CRT çağırır kullanılarak oluşturulan "C çalışma zamanı kitaplığı (CRT) çağıran bir yürütülebilir bir iplik iplik yönetimi için _beginthreadex ve _endthreadex işlevlerini kullanmalıdır [...], CRT feshedebilir düşük bellek koşullarında işlem. "
IInspectable

2

CreateThread()dilden bağımsız olan Windows API çağrısıdır. Sadece OS nesne dizisini yaratır ve bu evreye HANDLE döndürür. Tüm Windows uygulamaları iş parçacığı oluşturmak için bu çağrıyı kullanıyor. Tüm diller, bariz nedenlerden dolayı doğrudan API çağrısından kaçınır: 1. Kodunuzun işletim sistemine özgü olmasını istemezsiniz 2. API benzeri çağrı yapmadan önce bazı bakım işlemleri yapmanız gerekir: parametreleri ve sonuçları dönüştürmek, geçici depolama alanı ayırmak vb.

_beginthreadex()CreateThread()C'ye özgü olan C sarmalayıcıdır . İş parçacığına özel depolama tahsis ederek orijinal tek iş parçacıklı C f-n'lerin çok iş parçacıklı ortamda çalışmasını sağlar.

CRT kullanmazsanız, doğrudan bir aramadan kaçınamazsınız CreateThread(). CRT kullanıyorsanız, kullanmanız gerekir _beginthreadex()veya bazı CRT dizisi f-n'leri VC2005'ten önce düzgün çalışmayabilir.


1

CreateThread()düz sistem çağrısıdır. Uygulamanız Kernel32.dllbüyük olasılıkla başka nedenlerle zaten bağlantılı olacak şekilde uygulanmaktadır. Modern Windows sistemlerinde her zaman mevcuttur.

_beginthread()ve _beginthreadex()Microsoft C Runtime ( msvcrt.dll) içindeki sarmalayıcı işlevleridir . İki çağrı arasındaki farklar dokümantasyonda belirtilmiştir. Bu nedenle, Microsoft C Runtime kullanılabilir olduğunda veya uygulamanız ona statik olarak bağlıysa kullanılabilir. Saf Windows API ile kodlamadığınız sürece (kişisel olarak sıklıkla yaptığım gibi) muhtemelen bu kitaplığa da bağlanacaksınız.

Sorunuz tutarlı ve aslında tekrarlayan bir sorudur. Birçok API gibi, uğraşmamız gereken Windows API'de de yinelenen ve belirsiz işlevler vardır. Hepsinden kötüsü, dokümantasyon sorunu netleştirmiyor. Sanırım _beginthread()işlevler ailesi, 'nin manipülasyonu gibi diğer standart C işlevleriyle daha iyi entegrasyon için yaratıldı errno. _beginthread()böylece C çalışma zamanıyla daha iyi bütünleşir.

Buna rağmen, _beginthread()veya kullanmak için iyi nedenleriniz yoksa _beginthreadex()kullanmalısınız CreateThread(), çünkü çoğunlukla son çalıştırılabilir dosyanızda bir daha az kitaplık bağımlılığı elde edebilirsiniz (ve MS CRT için bu biraz önemlidir). Ayrıca, bu etki önemsiz olsa da, aramanın etrafına sarma kodunuz yoktur. Başka bir deyişle, bağlı kalmanın temel nedeninin , başlamak CreateThread()için kullanmanın iyi bir nedeni olmadığına inanıyorum _beginthreadex(). İşlevler tam olarak veya neredeyse aynıdır.

Kullanımına biri iyi bir neden _beginthread() olurdu eğer C ++ nesneleri düzgün açılmalıdır / tahrip olacağını (bunun yanlış görünüyor gibi) _endthread()denirdi.


Hiçbir belirsiz işlev çağrıları vardır hiç . CreateThreadbir iş parçacığı oluşturmak için Windows API çağrısıdır. CRT kullanıyorsanız (C veya C ++ ile programlama yaptığınız için), CRT _beginthread[ex]çağrılarını ( CreateThreadgerekli CRT başlatmaya ek olarak çağrı yapan) kullanarak iş parçacıkları oluşturmalısınız . _beginthreadEski varyant ile eski varyant arasındaki en önemli fark : İlki, yerel iş parçacığı tutamacının sahipliğini korurken, ikincisi sahipliği arayan kişiye devreder.
IInspectable

Nitpick: msvcrt.dllolduğu değil C çalışma zamanı DLL! Bkz blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273
Govind PARMAR

0

Diğer yanıtlar, bir Win32 API işlevini saran bir C çalışma zamanı işlevini çağırmanın sonuçlarını tartışmakta başarısız olur. Bu, DLL yükleyici kilitleme davranışını değerlendirirken önemlidir.

_beginthread{ex}Diğer cevaplarda tartışıldığı gibi herhangi bir özel C Runtime iş parçacığı / fiber bellek yönetimi olsun ya da olmasın , süreçlerin henüz yüklenmemiş olabileceği bir DLL'de (C çalışma zamanına dinamik bağlantı varsayılarak) uygulanır.

Çağrı güvenli değildir _beginthread*dan DllMain. Bunu, Windows "AppInit_DLLs" özelliğini kullanarak yüklenen bir DLL yazarak test ettim. _beginthreadex (...)Bunun yerine arama , belirli başlatma görevlerini gerçekleştirmek için yükleyici kilidinin serbest bırakılmasını bekleyen giriş noktası kilitlenmeleri CreateThread (...)nedeniyle önyükleme sırasında Windows'un birçok önemli parçasının çalışmayı durdurmasına neden olur DllMain.

Bu arada, bu aynı zamanda kernel32.dll'nin C çalışma zamanının da yaptığı birçok örtüşen dize işlevine sahip olmasının nedenidir - DllMainaynı tür durumlardan kaçınmak için bunları kullanın .


0

Jeffrey Richter'den Windows Uygulaması Hata Ayıklama kitabını okursanız, hemen hemen her durumda aramak _beginthreadexyerine aramanız gerektiğini açıklar CreateThread. _beginthreadsadece basitleştirilmiş bir paketleyicidir _beginthreadex.

_beginthreadexCreateThreadAPI'nin yapmayacağı belirli CRT (C RunTime) dahili bileşenlerini başlatır .

CRT işlevlerine çağrı CreateThreadkullanmak yerine API kullanırsanız bunun bir sonucu _begingthreadexbeklenmedik sorunlara neden olabilir.

Richter'den bu eski Microsoft Journal'a göz atın.


-2

Artık ikisi arasında hiçbir fark yok.

Bellek sızıntıları vb. Hakkındaki tüm yorumlar çok eski <VS2005 sürümlerine dayanmaktadır. Yıllar önce bazı stres testleri yaptım ve bu efsaneyi çürütebilirim. Microsoft bile stilleri örneklerinde karıştırır, neredeyse hiç _beginthread kullanmaz.



"CRT'nin çok iş parçacıklı sürümünün kullanılmasını gerektirir" alt sınıfına dayanarak, artık ve uzun yıllardır çok iş parçacıklı crt sürümü olmadığı için bunun dokümantasyon çöplüğü olduğunu varsayıyorum.
Lothar

"artık çok iş parçacıklı crt sürümü yok" - MSDN , "tek iş parçacıklı CRT'nin artık kullanılamadığını" iddia ediyor . İkiniz de haklı olamazsınız. Burada da MSDN ile gideceğim.
2016

Bu bir yazım hatasıydı, elbette tek iş parçacığının gittiğini ve çok iş parçacıklı olanın standart hale geldiğini ve gitmiş olanın iş parçacığı kullanmak veya kullanmamak arasındaki ayrım olduğunu kastetmiştim.
Lothar

Bu gerçekten garipleşiyor. Şimdi , hem bu ifadenin hem de belgelerin geri kalanının büyük olasılıkla yanlış olduğunu iddia etmek için şüphesiz doğru olan bir ifade ( "CRT'nin çok iş parçacıklı sürümünün kullanılmasını gerektirir" ) kullanıyorsunuz? Bu kesinlikle doğru gelmiyor.
IInspectable
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.