當前位置:首頁 » 編程語言 » c語言標准庫線程

c語言標准庫線程

發布時間: 2022-08-18 19:46:52

1. c語言多線程的概念

線程:線程是程序中的一個執行流,每個線程都有自己的專有寄存器(棧指針、程序計數器等),但代碼區是共享的,即不同的線程可以執行同樣的函數。
多線程:多線程是指程序中包含多個執行流,即在一個程序中可以同時運行多個不同的線程來執行不同的任務,也就是說允許單個程序創建多個並行執行的線程來完成各自的任務。
C語言的開始設計,並未設計多線程的機制,由於隨著軟硬體的發展及需求的發展。後來C語言才開發了線程庫以支持多線程的操作、應用。
主要基於linux介紹C多線程。在編譯C的多線程時候,一方面必須指定Linux C語言線程庫多線程庫pthread,才可以正確編譯(例如:gcc test.c -o test -lpthread);另一方面要包含有關線程頭文件#include <pthread.h>。

2. c語言怎麼創建線程和使用

進程的生命周期:
[1].創建 --- fork
[2].執行 --- a. exec
b.子進程實現代碼邏輯
[3].結束 --- exit _exit
僵屍態進程---wait waitpid
孤兒進程
--------------------------------------
進程存在的問題:
(1).進程的創建 --- 復制
(時間 和 空間的開銷很大)
(2).進程的運行 --- 調度-->

3. 對於C/C++標准庫的線程安全的一個疑問.該怎麼處理

c++和c本身都沒有標准多線程實現。

但是各個廠家都擴展了c,c++,例如微軟就有自己的多線程函數庫。

如果沒有標准庫的話,為什麼不把這樣重要的內容加入到標准中來呢?
c的發明很早,後續開發c編譯器的廠家只能發展自己的擴展庫,你不能說你自己的擴展庫就是一個標准,因為那是和版權問題相關的。

4. C語言如何實現多線程同時運行

1、點擊菜單欄的「Project」選項卡,下拉列表的最後一項「Project options...」是對當前工程的的屬性進行設置的。

5. C語言編譯器是否支持多線程

C語言編譯器有很多,只要不是太舊的都支持多線程。C語言本身是沒有多線程的概念的,都是操作系統提供支持,所以不同操作系統中的多線程實現起來可能完全不一樣。

6. C語言多線程的操作步驟

線程創建
函數原型:intpthread_create(pthread_t*restrict tidp,const pthread_attr_t *restrict attr,void *(*start_rtn)(void),void *restrict arg);
返回值:若是成功建立線程返回0,否則返回錯誤的編號。
形式參數:pthread_t*restrict tidp要創建的線程的線程id指針;const pthread_attr_t *restrict attr創建線程時的線程屬性;void *(start_rtn)(void)返回值是void類型的指針函數;void *restrict arg start_rtn的形參。
線程掛起:該函數的作用使得當前線程掛起,等待另一個線程返回才繼續執行。也就是說當程序運行到這個地方時,程序會先停止,然後等線程id為thread的這個線程返回,然後程序才會斷續執行。
函數原型:intpthread_join(pthread_tthread, void **value_ptr);
參數說明如下:thread等待退出線程的線程號;value_ptr退出線程的返回值。
返回值:若成功,則返回0;若失敗,則返回錯誤號。
線程退出
函數原型:voidpthread_exit(void *rval_ptr);
獲取當前線程id
函數原型:pthread_tpthread_self(void);
互斥鎖
創建pthread_mutex_init;銷毀pthread_mutex_destroy;加鎖pthread_mutex_lock;解鎖pthread_mutex_unlock。
條件鎖
創建pthread_cond_init;銷毀pthread_cond_destroy;觸發pthread_cond_signal;廣播pthread_cond_broadcast;等待pthread_cond_wait。

7. C語言多線程輸出不正常求高手指點

線程參數,傳地址使用動態分配吧,你只用一個buffer,後面的很可能就把前面的給覆蓋了。

把所有的輸出printf使用一個互斥的信號量同步一下就行了吧,C的標准庫不是線程安全的。

8. C語言怎樣實現多線程

首先你要有控制蛇移動方向的全局變數(定義在main以外因為線程函數也要調用它,每次鍵盤輸入都會修改它的值), 比如 char direction 'a' ==左 'w' == 右 'd'==上 's' == 下,然後你在移動時應該是在while裡面操作的吧,你每移動一步前都讀一下direction這個變數的數值然後再控制移動方向(注意s這個鍵可以忽略因為不會倒著走) 然後你可以用pthread.h這個庫 例子是 pthread t;// 定義一個線程 pthread_create(&t, null, listen_keyboard_input, null);//建立線程執行listen_keyboard_input這個函數 這個線程執行的函數 void listen_keyboard_input(){ while(應該通過某個信號來退出這個循環,從而表示游戲結束){ direction =getchar(); } } 但是這里存在同步問題, 比如當這個線程的getchar()在給direction輔助的同時,你控制貪吃蛇移動的線程正在調用 direction的值來判斷下一個移動方向,這就會出問題,所以要加一個鎖,叫 mutex lock;這個也定義成全局變數可以使各線程共享。 pthread_mutex_t mutex; //定義一個鎖 pthread_mutex_init(&mutex, null, null);//初始化 然後把函數修改成 void listen_keyboard_input(){ while(應該通過某個信號來退出這個循環,從而表示游戲結束){ pthread_mutex_lock(&mutex); direction =getchar(); pthread_mutex_unlock(&mutex); } } 另外一個控制貪吃蛇移動的時候也要加鎖 while(.....){ char c; pthread_mutex_lock(&mutex); c = direction; pthread_mutex_unlock(&mutex); switch(c){ ................ } ................................... } 這樣就好了 注意你的控制貪吃蛇移動的部分也必須要放在另外一個pthread 裡面執行,如果放在主線程, 主線程會一直等listen_keyboard_input而什麼事都不會做 你把這兩個線程用 pthread_create 創建完成後 用 t1.join(); t2.join(); 就可以使這兩個線程並發執行了 如果你用的是linux 來編譯的,你再輸入gcc 指令後加上 -lpthread 就可以了 還有什麼不懂的你可以多找找 pthread 類的例子

9. win32程序創建線程用c語言庫的_beginthread還是API的CreateThread哪種用的多

讓我們簡單回顧一下歷史。很早以前,是一個庫用於單線程應用程序,另一個庫用於多線程應
用程序。之所以採用這個設計,是由於標准C運行庫是在1970年左右發明的。要在很久很久之
後,才會在操作系統上出現線程的概念。標准C運行庫的發明者根本沒有考慮到為多線程應用
程序使用C運行庫的問題。讓我們用一個例子來了解可能遇到的問題。
以標准C運行庫的全局變數errno為例。有的函數會在出錯時設置該變數。假定現在有這樣的一
個代碼段:
BOOL fFailure = (system("NOTEPAD.EXE README.TXT") == -1);
if (fFailure) {
switch (errno) {
case E2BIG: // Argument list or environment too big
break;
case ENOENT: // Command interpreter cannot be found
break;
case ENOEXEC: // Command interpreter has bad format
break;
case ENOMEM: // Insufficient memory to run command
break;
}
}
假設在調用了system函數之後,並在執行if語句之前,執行上述代碼的線程被中斷了。另外還假
設,這個線程被中斷後,同一個進程中的另一個線程開始執行,而且這個新線程將執行另一個
C運行庫函數,後者設置了全局變數errno。當CPU後來被分配回第一個線程時,對於上述代碼
中的system函數調用,errno反映的就不再是正確的錯誤碼。為了解決這個問題,每個線程都需
要它自己的errno變數。此外,必須有某種機制能夠讓一個線程引用它自己的errno變數,同時
不能讓它去碰另一個線程的errno變數。
這僅僅是證明了「標准C/C++運行庫最初不是為多線程應用程序而設計」的眾多例子中的一個。
在多線程環境中會出問題的C/C++運行庫變數和函數有errno,_doserrno,strtok,_wcstok,
strerror,_strerror,tmpnam,tmpfile,asctime,_wasctime,gmtime,_ecvt和_fcvt等等。
為了保證C和C++多線程應用程序正常運行,必須創建一個數據結構,並使之與使用了C/C++運
行庫函數的每個線程關聯。然後,在調用C/C++運行庫函數時,那些函數必須知道去查找主調
線程的數據塊,從而避免影響到其他線程。
那麼,系統在創建新的線程時,是如何知道要分配這個數據塊的呢?答案是它並不知道。系統
並不知道應用程序是用C/C++來寫的,不知道你調用的函數並非天生就是線程安全的。保證線
程安全是程序員的責任。創建新線程時,一定不要調用操作系統的CreateThread函數。相反,
必須調用C/C++運行庫函數_beginthreadex:
unsigned long _beginthreadex(
void *security,
unsigned stack_size,
unsigned (*start_address)(void *),
void *arglist,
unsigned initflag,
unsigned *thrdaddr);
_beginthreadex函數的參數列表與CreateThread函數的一樣,但是參數名稱和類型並不完全一
樣。這是因為Microsoft的C/C++運行庫開發組認為,C/C++運行庫函數不應該對Windows數據類
型有任何依賴。_beginthreadex函數也會返回新建線程的句柄,就像CreateThread那樣。所以,
如果已經在自己的源代碼中調用了CreateThread函數,可以非常方便地用_beginthreadex來全
局替換所有CreateThread。但是,由於數據類型並不完相同,所以可能還必須執行一些類型轉
換,以便順利地通過編譯。為了簡化這個工作,我創建了一個名為chBEGINTHREADEX的宏,
並在自己的源代碼中使用:
typedef unsigned (__stdcall *PTHREAD_START) (void *);
#define chBEGINTHREADEX(psa, cbStack, pfnStartAddr, \
pvParam, fdwCreate, pdwThreadID) \
((HANDLE) _beginthreadex( \
(void *) (psa), \
(unsigned) (cbStackSize), \
(PTHREAD_START) (pfnStartAddr), \
(void *) (pvParam), \
(unsigned) (dwCreateFlags), \
(unsigned *) (pdwThreadID)))
根據Microsoft為C/C++運行庫提供的源代碼,很容易看出_beginthreadex能而CreateThread不能
做的事情。事實上,在搜索了Visual Studio安裝文件夾後,我在<Program Files>\Microsoft Visual
Studio 8\VC\crt\src\Threadex.c中找到了_beginthreadex的源代碼。為節省篇幅,這里沒有全部照
抄一遍。相反,我在這里提供了該函數的偽代碼版本,強調了其中最有意思的地方:
uintptr_t __cdecl _beginthreadex (
void *psa,
unsigned cbStackSize,
unsigned (__stdcall * pfnStartAddr) (void *),
void * pvParam,
unsigned dwCreateFlags,
unsigned *pdwThreadID) {
_ptiddata ptd; // Pointer to thread's data block
uintptr_t thdl; // Thread's handle
// Allocate data block for the new thread.
if ((ptd = (_ptiddata)_calloc_crt(1, sizeof(struct _tiddata))) == NULL)
goto error_return;
// Initialize the data block.
initptd(ptd);
// Save the desired thread function and the parameter
// we want it to get in the data block.
ptd->_initaddr = (void *) pfnStartAddr;
ptd->_initarg = pvParam;
ptd->_thandle = (uintptr_t)(-1);
// Create the new thread.
thdl = (uintptr_t) CreateThread((LPSECURITY_ATTRIBUTES)psa, cbStackSize,
_threadstartex, (PVOID) ptd, dwCreateFlags, pdwThreadID);
if (thdl == 0) {
// Thread couldn't be created, cleanup and return failure.
goto error_return;
}
// Thread created OK, return the handle as unsigned long.
return(thdl);
error_return:
// Error: data block or thread couldn't be created.
// GetLastError() is mapped into errno corresponding values
// if something wrong happened in CreateThread.
_free_crt(ptd);
return((uintptr_t)0L);
}
對於_beginthreadex函數,以下幾點需要重點關注。
􀂾 每個線程都有自己的專用_tiddata內存塊,它們是從C/C++運行庫的堆(heap)上分配
的。
􀂾 傳給_beginthreadex的線程函數的地址保存在_tiddata內存塊中。(_tiddata結構在
Mtdll.h文件的C++源代碼中。)純粹是為了增加趣味性,我在下面重現了這個結構。要
傳入_beginthreadex函數的參數也保存在這個數據塊中。
􀂾 _beginthreadex確實會在內部調用CreateThread,因為操作系統只知道用這種方式來
創建一個新線程。
􀂾 CreateThread函數被調用時,傳給它的函數地址是_threadstartex(而非
pfnStartAddr)。另外,參數地址是_tiddata結構的地址,而非pvParam。
􀂾 如果一切順利,會返回線程的句柄,就像CreateThread那樣。任何操作失敗,會返回0。
struct _tiddata {
unsigned long _tid; /* thread ID */
unsigned long _thandle; /* thread handle */
int _terrno; /* errno value */
unsigned long _tdoserrno; /* _doserrno value */
unsigned int _fpds; /* Floating Point data segment */
unsigned long _holdrand; /* rand() seed value */
char* _token; /* ptr to strtok() token */
wchar_t* _wtoken; /* ptr to wcstok() token */
unsigned char* _mtoken; /* ptr to _mbstok() token */
/* following pointers get malloc'd at runtime */
char* _errmsg; /* ptr to strerror()/_strerror() buff */
wchar_t* _werrmsg; /* ptr to _wcserror()/__wcserror() buff */
char* _namebuf0; /* ptr to tmpnam() buffer */
wchar_t* _wnamebuf0; /* ptr to _wtmpnam() buffer */
char* _namebuf1; /* ptr to tmpfile() buffer */
wchar_t* _wnamebuf1; /* ptr to _wtmpfile() buffer */
char* _asctimebuf; /* ptr to asctime() buffer */
wchar_t* _wasctimebuf; /* ptr to _wasctime() buffer */
void* _gmtimebuf; /* ptr to gmtime() structure */
char* _cvtbuf; /* ptr to ecvt()/fcvt buffer */
unsigned char _con_ch_buf[MB_LEN_MAX];
/* ptr to putch() buffer */
unsigned short _ch_buf_used; /* if the _con_ch_buf is used */
/* following fields are needed by _beginthread code */
void* _initaddr; /* initial user thread address */
void* _initarg; /* initial user thread argument */
/* following three fields are needed to support signal handling and runtime errors */
void* _pxcptacttab; /* ptr to exception-action table */
void* _tpxcptinfoptrs;/* ptr to exception info pointers */
int _tfpecode; /* float point exception code */
/* pointer to the of the multibyte character information used by the thread */
pthreadmbcinfo ptmbcinfo;
/* pointer to the of the locale information used by the thread */
pthreadlocinfo ptlocinfo;
int _ownlocale; /* if 1, this thread owns its own locale */
/* following field is needed by NLG routines */
unsigned long _NLG_dwCode;
/*
* Per-Thread data needed by C++ Exception Handling
*/
void* _terminate; /* terminate() routine */
void* _unexpected; /* unexpected() routine */
void* _translator; /* S.E. translator */
void* _purecall; /* called when pure virtual happens */
void* _curexception; /* current exception */
void* _curcontext; /* current exception context */
int _ProcessingThrow; /* for uncaught_exception */
void* _curexcspec; /* for handling exceptions thrown from std::unexpected */
#if defined (_M_IA64) || defined (_M_AMD64)
void* _pExitContext;
void* _pUnwindContext;
void* _pFrameInfoChain;
unsigned __int64 _ImageBase;
#if defined (_M_IA64)
unsigned __int64 _TargetGp;
#endif /* defined (_M_IA64) */
unsigned __int64 _ThrowImageBase;
void* _pForeignException;
#elif defined (_M_IX86)
void* _pFrameInfoChain;
#endif /* defined (_M_IX86) */
_setloc_struct _setloc_data;
void* _encode_ptr; /* EncodePointer() routine */
void* _decode_ptr; /* DecodePointer() routine */
void* _reserved1; /* nothing */
void* _reserved2; /* nothing */
void* _reserved3; /* nothing */
int _ cxxReThrow; /* Set to True if it's a rethrown C++ Exception */
unsigned long __initDomain; /* initial domain used by _beginthread[ex] for managed
function */
};
typedef struct _tiddata * _ptiddata;
為新線程分配並初始化_tiddata結構之後,接著應該知道這個結構是如何與線程關聯的。來看看
_threadstartex函數(它也在C/C++運行庫的Threadex.c文件中)。下面是我為這個函數及其helper
函數__callthreadstartex編寫的偽代碼版本:
static unsigned long WINAPI _threadstartex (void* ptd) {
// Note: ptd is the address of this thread's tiddata block.
// Associate the tiddata block with this thread so
// _getptd() will be able to find it in _callthreadstartex.
TlsSetValue(__tlsindex, ptd);
// Save this thread ID in the _tiddata block.
((_ptiddata) ptd)->_tid = GetCurrentThreadId();
// Initialize floating-point support (code not shown).
// call helper function.
_callthreadstartex();
// We never get here; the thread dies in _callthreadstartex.
return(0L);
}
static void _callthreadstartex(void) {
_ptiddata ptd; /* pointer to thread's _tiddata struct */
// get the pointer to thread data from TLS
ptd = _getptd();
// Wrap desired thread function in SEH frame to
// handle run-time errors and signal support.
__try {
// Call desired thread function, passing it the desired parameter.
// Pass thread's exit code value to _endthreadex.
_endthreadex(
( (unsigned (WINAPI *)(void *))(((_ptiddata)ptd)->_initaddr) )
( ((_ptiddata)ptd)->_initarg ) ) ;
}
__except(_XcptFilter(GetExceptionCode(), GetExceptionInformation())){
// The C run-time's exception handler deals with run-time errors
// and signal support; we should never get it here.
_exit(GetExceptionCode());
}
}
關於_threadstartex函數,要注意以下重點:
􀂾 新的線程首先執行RtlUserThreadStart (在NTDLL.dll文件中),然後再跳轉到
_threadstartex。
􀂾 _threadstartex惟一的參數就是新線程的_tiddata內存塊的地址。
􀂾 TlsSetValue是一個操作系統函數,它將一個值與主調線程關聯起來。這就是所謂的線
程本地存儲(Thread Local Storage,TLS),詳情參見第21章。_threadstartex函數將
_tiddata內存塊與新建線程關聯起來。
􀂾 在無參數的helper函數_callthreadstartex中,一個SEH幀將預期要執行的線程函數包圍
起來。這個幀處理著與運行庫有關的許多事情——比如運行時錯誤(如拋出未被捕捉的
C++異常)——和C/C++運行庫的signal函數。這一點相當重要。如果用CreateThread函
數新建了一個線程,然後調用C/C++運行庫的signal函數,那麼signal函數不能正常工作。
􀂾 預期要執行的線程函數會被調用,並向其傳遞預期的參數。前面講過,函數的地址和
參數由_beginthreadex保存在TLS的_tiddata數據塊中;並會在_callthreadstartex中從
TLS中獲取。
􀂾 線程函數的返回值被認為是線程的退出代碼。
注意_callthreadstartex不是簡單地返回到_threadstartex,繼而到RtlUserThreadStart;
如果是那樣的話,線程會終止運行,其退出代碼也會被正確設置,但線程的_tiddata
內存塊不會被銷毀。這會導致應用程序出現內存泄漏。為防止出現這個問題,會調用
_endthreadex(也是一個C/C++運行庫函數),並向其傳遞退出代碼。
最後一個需要關注的函數是_endthreadex(也在C運行庫的Threadex.c文件中)。下面是我編寫的該
函數的偽代碼版本:
void __cdecl _endthreadex (unsigned retcode) {
_ptiddata ptd; // Pointer to thread's data block
// Clean up floating-point support (code not shown).
// Get the address of this thread's tiddata block.
ptd = _getptd_noexit ();
// Free the tiddata block.
if (ptd != NULL)
_freeptd(ptd);
// Terminate the thread.
ExitThread(retcode);
}
對於_endthreadex函數,要注意幾下幾點:
􀂾 C運行庫的_getptd_noexit函數在內部調用操作系統的TlsGetValue函數,後者獲取主調
線程的tiddata內存塊的地址。
􀂾 然後,此數據塊被釋放,調用操作系統的ExitThread函數來實際地銷毀線程。當然,
退出代碼會被傳遞,並被正確地設置。
在本章早些時候,我曾建議大家應該避免使用ExitThread函數。這是千真萬確的,而且我在這
里並不打算自相矛盾。前面說過,此函數會殺死主調線程,而且不允許它從當前執行的函數返
回。由於函數沒有返回,所以構造的任何C++對象都不會被析構。現在,我們又有了不調用
ExitThread函數的另一個理由:它會阻止線程的_tiddata內存塊被釋放,使應用程序出現內存泄
漏(直到整個進程終止)。
Microsoft的C++開發團隊也意識到,總有一些開發人員喜歡調用ExitThread。所以,他們必須
使這成為可能,同時盡可能避免應用程序出現內存泄漏的情況。如果真的想要強行殺死自己的
線程,可以讓它調用_endthreadex(而不是ExitThread)來釋放線程的_tiddata塊並退出。不過,
我並不鼓勵你調用_endthreadex。
現在,你應該理解了C/C++運行庫函數為什麼要為每一個新線程准備一個獨立的數據塊,而且
應該理解了_beginthreadex如何分配和初始化此數據塊,並將它與新線程關聯起來。另外,你還
應理解了_endthreadex函數在線程終止運行時是如何釋放該數據塊的。
一旦這個數據塊被初始化並與線程關聯,線程調用的任何需要「每線程實例數據」的C/C++運
行庫函數都可以輕易獲取主調線程的數據塊的地址(通過TlsGetValue),並操縱線程的數據。這
對函數來說是沒有問題的。但是,對於errno之類的全局變數,它又是如何工作的呢?errno是在
標准C headers中定義的,如下所示:
_CRTIMP extern int * __cdecl _errno(void);
#define errno (*_errno())
int* __cdecl _errno(void) {
_ptiddata ptd = _getptd_noexit();
if (!ptd) {
return &ErrnoNoMem;
} else {
return (&ptd->_terrno);
}
}
任何時候引用errno,實際都是在調用內部的C/C++運行庫函數_errno。該函數將地址返回給「與
主調線程關聯的數據塊」中的errno數據成員。注意,errno宏被定義為獲取該地址的內容。這
個定義是必要的,因為很可能寫出下面這樣的代碼:
int *p = &errno;
if (*p == ENOMEM) {
...
}
如果內部函數_errno只是返回errno的值,上述代碼將不能通過編譯。
C/C++運行庫還圍繞特定的函數放置了同步原語(synchronization primitives)。例如,如果兩個
線程同時調用malloc,堆就會損壞。C/C++運行庫函數阻止兩個線程同時從內存堆中分配內存。
具體的辦法是讓第2個線程等待,直至第1個線程從malloc函數返回。然後,才允許第2個線程進
入。(線程同步將在第8章和第9章詳細討論。)顯然,所有這些額外的工作影響了C/C++運行庫的
多線程版本的性能。
C/C++運行庫函數的動態鏈接版本被寫得更加泛化,使其可以被使用了C/C++運行庫函數的所有
運行的應用程序和DLL共享。因此,庫只有一個多線程版本。由於C/C++運行庫是在一個DLL
中提供的,所以應用程序(.exe文件)和DLL不需要包含C/C++運行庫函數的代碼,所以可以更小
一些。另外,如果Microsoft修復了C/C++運行庫DLL的任何bug,應用程序將自動獲得修復。
就像你期望的一樣,C/C++運行庫的啟動代碼為應用程序的主線程分配並初始化了一個數據塊。
這樣一來,主線程就可以安全地調用任何C/C++運行庫函數。當主線程從其入口函數返回的時
候,C/C++運行庫函數會釋放關聯的數據塊。此外,啟動代碼設置了正確的結構化異常處理代
碼,使主線程能成功調用C/C++運行庫的signal函數。
6.7.1 用_beginthreadex 而不要用CreateThread 創建線程
你可能會好奇,假如調用CreateThread而不是C/C++運行庫的_beginthreadex來創建新線程,會
發生什麼呢?當一個線程調用一個需要_tiddata結構的C/C++運行庫函數時,會發生下面的情
況。(大多數C/C++運行庫函數都是線程安全的,不需要這個結構。)首先,C/C++運行庫函數嘗
試取得線程數據塊的地址(通過調用TlsGetValue)。如果NULL被作為_tiddata塊的地址返回,表
明主調線程沒有與之關聯的_tiddata塊。在這個時候,C/C++運行庫函數會為主調線程分配並初
始化一個_tiddata塊。然後,這個塊會與線程關聯(通過TlsSetValue) ,而且只要線程還在運行,
這個塊就會一直存在並與線程關聯。現在,C/C++運行庫函數可以使用線程的_tiddata塊,以後
調用的任何C/C++運行庫函數也都可以使用。
當然,這是相當誘人的,因為線程(幾乎)可以順暢運行。但事實上,問題還是有的。第一個
問題是,假如線程使用了C/C++運行庫的signal函數,則整個進程都會終止,因為結構化異常處
理(SEH)幀沒有就緒。第二個問題是,假如線程不是通過調用_endthreadex來終止的,數據
塊就不能被銷毀,從而導致內存泄漏。(對於一個用CreateThread函數來創建的線程,誰會調用
_endthreadex呢?)

10. 標准C/C++包不包含socket相關和線程之類的函數

不包含
C++標准程序庫裡面沒有socket的相關支持
這些支持要依靠具體的C/C++版本提供的庫來支持
另外,線程方面,BOOST庫(很可能成為下一個版本的c++標準的一部分)有支持

熱點內容
如何測試電視的配置 發布:2025-01-19 21:00:48 瀏覽:609
sql日期格式轉換字元 發布:2025-01-19 20:58:45 瀏覽:878
路由器管理密碼是什麼忘了怎麼辦 發布:2025-01-19 20:34:35 瀏覽:427
java方法定義 發布:2025-01-19 20:20:50 瀏覽:404
kr腳本 發布:2025-01-19 20:17:41 瀏覽:518
幫我開啟存儲 發布:2025-01-19 20:17:39 瀏覽:813
s9存儲縮水 發布:2025-01-19 20:08:06 瀏覽:335
2b2t的伺服器編號是什麼 發布:2025-01-19 19:58:55 瀏覽:874
androidstudio下載與安裝 發布:2025-01-19 19:58:14 瀏覽:560
拉鉤演算法 發布:2025-01-19 19:58:14 瀏覽:866