2011-03-02 15 views
9

recv işlevi bekleyen bir iş parçacığı nasıl kesilir?

size_t recvLen = recv(sock, buf, 512, 0); 

bunu kesintiye ile bu konuyu sonlandırmak istiyorum:

ben recv işlevini asılı bir soket dinleyici var. MSDN diyor:

böyle recv gibi bir engelleme Winsock çağrı verilirken, Winsock çağrı tamamlamak için önce bir ağ olayı için beklemeniz gerekebilir. Winsock aynı iş parçacığı üzerinde planlanan bir asenkron yordam çağrısı (APC) tarafından kesilebilir, bu durumda, bir Duyurulabilir bekleme gerçekleştirir.

Bunu nasıl yapabilirim?

+0

Bir APC'yi iş parçacığına kuyruğa sokarak closesocket'ı kullanın; bu, soketin kapalı olması nedeniyle bir hatayla geri dönmesine neden olur. – paulm

cevap

9

Bir APC'yi QueueUserAPC aracılığıyla kuyruğa sokarak kesebilirsiniz. Bununla birlikte, APC'deki ipliği sonlandırmak büyük olasılıkla güvenli değildir. Bir APC'nin sıraya konması, recv'u sonlandırmaz, sadece keser; APC geri döndüğünde, tekrar recv beklemeye geri döner.

recv'u tamamen durdurmak istiyorsanız, select numaralı veriyi kullanana kadar bir süre beklemeniz gerekir. Ardından veri beklemeye devam edip etmeyeceğinizi veya her bir zaman aşımına devam edip etmeyeceğinizi kontrol edebilirsiniz.

+2

APC çağrısında çağrı kapanır() ve geri döner, async soketi veya kötüye ihtiyaç yoktur TerminateThread çağrısı :) – paulm

-1

Errrr ... Aynı konu üzerinde bir APC gerçekleştirin mi? :-))

Cidden, buradaki amacınızın ne olduğu açık değil.
Yalnızca iş parçacığını sonlandırmak isterseniz, TerminateThread işlevini kullanın.
Bu belirli aramayı kesmek isterseniz, soketi kapatabilirsiniz.

+0

sonlandırma iş parçacığı, DLL'leri bildirmediğinden ve iş parçacığının temizlenmesine izin vermediğinden kullanılmamalıdır. Soketi kapatmak mümkündür, ancak sokete hala ihtiyacınız olabilir. –

0

Bu sorunu çözmenin en iyi yolu, soketi engelleme olmayan G/Ç moduna sokmaktır, böylece iş parçacığı hiçbir zaman içeride recv() öğesini (veya bu iletide() öğesinde) engelleyemez. İplik sadece select() (veya WaitMultipleObjects()) içinde bloke edilmelidir. Bu durumda, sokete veri geldiğinde select() (veya WaitMultipleObjects()) çağrısı geri dönecektir (bu durumda engellemeden yeni veriyi almak için recv() yi çağırabilirsiniz), fakat ayrıca seçim yapabilirsiniz()/Başka bir şey olduğunda WaitMultipleObjects() geri döner; Örneğin. ana iş parçacığı bir istemi aldığında. Select() yöntemini kullanıyorsanız, bu komut istemi, farklı bir yuva çiftinde bir bayt gönderen ana iş parçacığı olabilir (yuva çiftinin bir ucunu tutan ana iş parçacığı ve diğer ucunu tutan G/Ç iş parçacığı ile); WaitMultipleObjects() kullanıyorsanız, WaitMultipleObjects() işlevinin dönmesine neden olacak standart Windows olay/sinyal yöntemlerinden herhangi birini kullanabileceğinizi düşünüyorum.

+1

'select()' işlevini kullanmak için soketi blokaj yapmayan kipe geçirmeniz gerekmez. 'Select()' tuşlarını bloke ederek kullanabilirsiniz. '' Recv() 'çağrılmadan önce soketin okunabilir olduğundan emin olmak için' select() 'i çağırınız, daha sonra soket engelleme modunda olsa bile' recv() bloklanmayacaktır. –

+0

Soketin tıkanmaz duruma getirilmesinden daha kolay/daha iyi olduğundan emin değilim. Şimdi bir kod satırı eklemek yerine, sokete her potansiyel olarak bloke eden çağrıdan önce bir kod satırı eklemeniz gerekir (ve siz ya da gelecekteki kod koruyucular, bunu yapmayı unutursanız, ince ve zor bir şekilde Programınızda, birileri izlemek için çok fazla zaman ayırabilecek bir hatayı tespit etmek için) –

+0

Ayrıca, check-with-select-before-recv() yaklaşımı her zaman güvenilir şekilde çalışmaz: http://stackoverflow.com/ a/5352634/131930 –

3

Daha fazla veri almak istemiyorsanız, soketi istediğiniz zaman öldürebilirsiniz. Bunun için close() öğesini çağırın, söz konusu işlev hemen bir hata döndürecektir.

Geçmişte yaptığım şey, bir zaman aşımıyla başka bir iş parçacığının çalıştırılmasıdır, bekleme süresinden sonra "ölme" bayrağı ayarlanmadığında soketi öldürmez.

1

recv'dan önce soket arabelleğini kontrol etmek, select() desteği için çok fazla kaplama yerine daha esnektir. Ağ arabelleğindeki verilerin okunup okunmadığını görmek için ioctlsocket(SockHandle, FIONREAD, Longint(CountInBuffer)) numaralı telefonu arayabilir ve ardından recv(SockHandle, buff, CountInBuffer, 0) numaralı telefonu arayabilirsiniz. Böylelikle, buff'ı CountInBuffer ile yeterince ayırırsanız, tüm ağ okuma arabelleğini okumak için tek bir geri arama çağrısı yapabilirsiniz.Aksi takdirde, geleneksel yol olan ağ arabelleğini okumak için bir döngüde recv'yi çağırmanız gerekir. Her iki durumda da, hala CountInBuffer'un kısıtlamalarındasınız.

-1

Engellemeyi engellemenin tek yolu, recv() numaralı çağrıyı kesmek ve tamamen çıkmak için, soketi engellenen başka bir konu bağlamından kapatmaktır. Bu bir seçenek değilse, o zaman soket mantığınızı yeniden yazmanız gerekir. Engelleme olmayan veya eşzamansız I/O'ları kullanmanın en iyi yolu bu şekilde recv() (veya bunun için WSARecv()) hiçbir zaman engellenmez ve okuma işlemi yapılırken yapmanız gereken her şeyi (iş parçacığı sonlandırma koşullarını kontrol etme gibi) yapabilirsiniz. arka fon.

+0

Sadece, diğer iş parçacığının sizin için kapatmış olabileceği bir yarış koşulunun olmadığından emin olun, yoksa zaten başka bir soket (yeni soket) için açılmış bir soket tanımlayıcıyı kapatıyor olabilirsiniz [? ] – rogerdpack

+0

re: async, WaitForMultipleObjects http://ffmpeg.org/pipermail/ffmpeg-devel/2013-Defember/152211.html – rogerdpack

+0

kullanarak mümkündür. "WaitFor ... Object (s)' işlevlerinden herhangi birini kullanamazsınız. Soket tutamakları ile. Olay işlemlerini, yerine kilitleme işlemleri tamamlandığında 'SetEvent()' işlevini çağırmak yerine, CreateEvent() 'den kullanmanız gerekir. Ya da 'WASEventSelect()' ve 'WSAWaitForMultipleEvents()' ile 'WSACreateEvent()' işlevini kullanın. Veya 'CreateIoCompletionPort()' 'GetQueuedCompletionStatus()' ile kullanın. –

İlgili konular