2011-12-25 9 views
5

मैं कोरआउट सिस्टम को लागू करने के लिए setjmp()/longjmp() का उपयोग करना चाहता हूं। फिर मैं इसका परीक्षण करने के लिए एक छोटी सी फ़ाइल को कोड करने का निर्णय लेता हूं। MinGW में, यह ठीक है; मुझे वह परिणाम मिला जो मैं चाहता हूं। लेकिन जब मैं MSVC++, कार्यक्रम दुर्घटनाओं में यह संकलन: "पहुँच उल्लंघन"एमएसवीसी पर setjmp/longjmp क्रैश क्यों होता है जब यह MinGW में नहीं था?

#include <stdio.h> 
    #include <stdlib.h> 
    #include <setjmp.h> 

    jmp_buf a; 
    int is_invoke=0; 

    void 
    action_1() 
    { 
     for (;;) { 
      printf("hello~~~A\n"); 
      if(!setjmp(a)) { 
      is_invoke=1; 
      return; 
      } 
     } 
    } 

    void 
    func() 
    { 
     if (is_invoke) { 
     longjmp(a,1); 
     } 
     action_1(); 
     printf("end\n"); 
    } 

    void 
    dummy() 
    { 
     ; 
    } 

    int 
    main(int argc, char *argv[]) 
    { 
     for (;;) { 
      func(); 
      dummy(); 
     } 
     return 0; 
    } 
+0

मैं कैसे setjmp/longjmp वास्तव में अनुकूलक बँधा हुआ के बारे में थोड़ी देर पहले एक लेख पढ़ा है, और एक बार वे इसके बारे में कार्यक्रम छुटकारा पा लिया है कि वे काफी तेज पर काम कर रहे थे। – Bill

+1

प्रश्न: एमएसवीसी ++ का संस्करण क्या है? प्रश्न: बिल्कुल यह कहां दुर्घटनाग्रस्त हो गया? क्या आपने विजुअल स्टूडियो डीबगर में चलाने का प्रयास किया था? प्रश्न: क्या आपके एमएसवीसी ++ संकलन में कोई चेतावनी या त्रुटियां थीं? – paulsm4

+0

एमएसवीसी का मेरा संस्करण 2008 है। Longjmp में दुर्घटना। हाँ। संकलन पर कोई त्रुटि और चेतावनी नहीं है। यह एक रनटाइम त्रुटि – TZW

उत्तर

7

setjmp के लिए आदमी पृष्ठ बताता है:

setjmp() से बाद में उपयोग के env में ढेर संदर्भ/पर्यावरण बचाता है longjmp()। यदि कार्य है जिसे setjmp() रिटर्न कहा जाता है तो स्टैक संदर्भ को अमान्य कर दिया जाएगा।

एक सरल कार्यान्वयन में आप लगता है हो सकता है कि एक jmp_buf को ढेर सूचक और करने के लिए कूद करने के लिए एक पता रीसेट करने के लिए पता है। जैसे ही आप jmp_buf को सहेजने वाले फ़ंक्शन से वापस आते हैं, jmp_buf द्वारा इंगित स्टैक फ्रेम अब मान्य नहीं है और तुरंत दूषित हो सकता है।

या दूसरे शब्दों में, आप केवल सुपर -return कथन के रूप में कार्य करने के लिए लंबे समय तक भरोसा कर सकते हैं - कभी भी गहराई से नहीं जाना चाहिए।

मुझे लगता है कि यह आपके लिए mingw (और मेरे लिए लिनक्स पर) में काम करता है यह कार्यान्वयन-विशिष्ट और संभवतः भाग्य से नीचे है। एक और तरीका है - क्या आपने Simon Tatham's evil coroutine macros निबंध पढ़ा है?

+0

ठीक ~ मैं जाँच setjmp का विकी? – TZW

+0

@TZW: नहीं; समस्या यह है कि आप 'longjmp()' को कॉल करने से पहले 'setjmp()' नामक फ़ंक्शन से वापस लौटे। –

+0

@Jonathan Leffler: तो आप मुझे बता सकते हैं वहाँ वैध एक jmp_buf के संदर्भ की जांच करने का आसान तरीका है या नहीं, सर? – TZW

1

आप coroutines के लिए setjmp/longjmp का उपयोग नहीं कर सकते हैं। विंडोज़ पर POSIX, या फाइबर (CreateFiber, आदि) पर makecontext/swapcontext का उपयोग करें।

4

चूंकि आप अपरिभाषित व्यवहार का आह्वान कर रहे हैं, इसलिए एक कंपाइलर को क्रैश करने के लिए ठीक है और दूसरा काम करने के लिए ठीक है। दोनों सही हैं - यह अपरिभाषित व्यवहार की सुंदरता है।

समस्या यह है कि एक सहेजा गया संदर्भ - jmp_buf - केवल तब तक मान्य रहता है जब इसे setjmp() नामक फ़ंक्शन को वापस नहीं किया जाता है।

C99 मानक (अब वर्तमान मानक है, लेकिन यह शब्द काफी बदल गया है की संभावना नहीं है) का कहना है:

§7.13.2.1 longjmp समारोह

longjmp समारोह बचाया वातावरण पुनर्स्थापित करता है setjmp मैक्रो के हालिया आमंत्रण के साथ jmp_buf तर्क के साथ प्रोग्राम के उसी आमंत्रण में मैक्रो। अगर ऐसी कोई मंगलाचरण किया गया है, या युक्त setjmp मैक्रो के आह्वान समारोह अंतरिम में निष्पादन 208) समाप्त कर दिया है, या यदि setjmp मैक्रो की मंगलाचरण variably साथ एक पहचानकर्ता के दायरे के भीतर था संशोधित प्रकार और निष्पादन ने अंतरिम में उस दायरे को छोड़ दिया है, व्यवहार अपरिभाषित है।

208) उदाहरण के लिए, एक return बयान को क्रियान्वित करने या क्योंकि एक और longjmp कॉल नेस्टेड कॉल के सेट में पहले एक समारोह में एक setjmp मंगलाचरण के लिए एक हस्तांतरण का कारण बना है द्वारा।

आपका कोड action_1() से बाहर निकलने है लगभग तुरंत, प्रतिपादन jmp_bufsetjmp() बेकार ने बचा लिया।


मैं कुछ साल पहले setjmp() और longjmp() का यह छोटा प्रदर्शन बनाया। यह आपकी मदद कर सकता है।

/* 
@(#)File:   $RCSfile: setjmp.c,v $ 
@(#)Version:  $Revision: 1.1 $ 
@(#)Last changed: $Date: 2009/10/01 16:41:04 $ 
@(#)Purpose:  Demonstrate setjmp() and longjmp() 
@(#)Author:   J Leffler 
@(#)Copyright:  (C) JLSS 2009 
*/ 


#include <stdio.h> 
#include <setjmp.h> 
#include <stdlib.h> 

static jmp_buf target_location; 

static void do_something(void) 
{ 
    static int counter = 0; 
    if (++counter % 10 == 0) 
     printf("---- doing something: %3d\n", counter); 
    if (counter % 1000 == 0) 
    { 
     printf("||-- doing_something: calling longjmp() with value -1\n"); 
     longjmp(target_location, -1); 
    } 
} 

static void do_something_else(int i, int j) 
{ 
    printf("-->> do_something_else: (%d,%d)\n", i, j); 
    do_something(); 
    if (i > 2 && j > 2 && j % i == 2) 
    { 
     printf("||-- do_something_else: calling longjmp() with value %d\n", (i + j) % 100); 
     longjmp(target_location, (i + j) % 100); 
    } 
    printf("<<-- do_something_else: (%d,%d)\n", i, j); 
} 

static void doing_stuff(void) 
{ 
    int i; 
    printf("-->> doing_stuff()\n"); 
    for (i = rand() % 15; i < 30; i++) 
    { 
     int j; 
     do_something(); 
     for (j = rand() % 10; j < 20; j++) 
     { 
      do_something_else(i, j); 
     } 
    } 
    printf("<<-- doing_stuff()\n"); 
} 

static void manage_setjmp(void) 
{ 
    printf("-->> manage_setjmp()\n"); 
    switch (setjmp(target_location)) 
    { 
    case 0: 
     /* Initial return - get on with doing stuff */ 
     doing_stuff(); 
     break; 
    case -1: 
     /* Error return - terminate */ 
     printf("<<-- manage_setjmp() - error return from setjmp()\n"); 
     return; 
    default: 
     /* NB: not officially possible to assign the return from setjmp() */ 
     printf("---- manage_setjmp() - non-error return from setjmp()\n"); 
     doing_stuff(); 
     break; 
    } 
    printf("<<-- manage_setjmp()\n"); 
} 

int main(void) 
{ 
    printf("-->> main()\n"); 
    manage_setjmp(); 
    printf("<<-- main()\n"); 
    return(0); 
} 
संबंधित मुद्दे