A. c語言多線程如何運行指定時間
第一步: 將源文件1(1.c)修改為如下形式: #include "print.h" #include "2.c" int main(void) { printHello(); return 0; } 其中的2.c就是源文件2的文件名 第二步,將三個文件保存到同一目錄中 第三步,打開TC2,執行FILE-CHANGE DIR,將工作目錄換到三個文件所在的目錄。 第四步,在TC2中打開1.c文件,編譯運行。 建議不要再使用TC2這個相對原始的IDE了,上面介紹的這個方法也並不是標准方法,建議使用TC2006/VC/BCB等現代的IDE環境,如果實在是舍棄不下DOS字元界面,那就試試GCC吧!
B. c語言如何編寫一個簡單的多線程程序
這是一個多線程例子,裡面只有兩個線程,是生產者/消費者模式,已編譯通毀舉宏過,注釋很詳細,x0dx0a如下:x0dx0ax0dx0a/* 以生答蠢產者和消費者模型問題來闡述Linux線程的控制和通信你 x0dx0a 生產者線程將生產的產品送入緩沖區,消費者線程則從中取出產品。x0dx0a 緩沖區有N個,是一個環形的緩沖池。x0dx0a */纖冊x0dx0a#include
C. c語言 多線程套接字編程
你ip的初始值是多少?
有沒有重定向過標准輸入?
另一個線程是否也阻塞在讀標准輸入上?
D. 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呢?)
E. C語言多線程的優勢
線程程序作為一種多任務、並發的工作方式,當然有其存在優勢:
提高應用程序響應:
這對圖形界面的程序尤其有意義,當一個操作耗時很長時,整個系統都會等待這個操作,此時程序不會響應鍵盤、滑鼠、菜單的操作,而使用多線程技術,將耗時長的操作(time consuming)置於一個新的線程,可以避免這種尷尬的情況。
使多CPU系統更加有效:
操作系統會保證當線程數不大於CPU數目時,不同的線程運行於不同的CPU上。
改善程序結構:
一個既長又復雜的進程可以考慮分為多個線程,成為幾個獨立或半獨立的運行部分,這樣的程序會利於理解和修改。
F. 用C語言寫多線程程序
thread_creation.c
gcc thread_creation.c
會在當前目錄山配行下逗嘩,生成可執行賣襲的a.out文件
./a.out
G. c語言怎麼同時運行4段
可以使用多線程的辦法,同時運行的方法如下:
1)使用void*myfunc(void*args){;
2)在intmain(){limian寫四組pthread,pthread_create(),pthread_join();
3)最後return0。
多線程(multithreading),是指從軟體或者硬體上實現多個線程並發執行的技術。具有多線程能力的計算機因有硬體支持而能夠在同一時間執行多於一個線程,進而提升整體處理性能。具有這種能力的系統包括對稱多處理機、多核心處理器以及晶元級多處理或同時多線程處理器。在一個程序中,這些獨立運行的程序片段叫作「線程」(Thread),利用它編程的概念就叫作「多線程處理」。
程序語言有多種分類方法,大部分程序語言都是演算法描述型語言,如C/C++、Java等,還有一部分是數據描述型語言,如HTML等標記語言。按照編程技術難易程度可分為低級語言(機器語言、匯編語言)和高級語言;按照程序語言設計風格可分為命令式語言(過程化語言)、結構化語言、面向對象語言、函數式語言、腳本語言等;按照語言應用領域可分為通用程序語言(GPPL)和專用程序語言(DSL);按照程序執行方式,可分為解釋型語言(如JavaScript、Python、Perl、R等),編譯型語言(如C/C++等),編譯+解釋型語言(如Java、PHP等)。
H. C語言中 怎麼實現雙線程 或者 父子線程啊
運行一個程序,這個運行實體就是一個「進程」。
例如,用滑鼠雙擊IE瀏覽器的圖標,你運行了一個IE「進程」。第一個窗未關,你又用滑鼠雙擊IE瀏覽器的圖標,又出來一個瀏覽器的窗。這時,你運行了同一個程序的兩個進程。
對於自己寫的程序也如此。運行它,這個運行實體就是一個「進程」。同時運行兩個,就是兩個進程。計算機分別對兩個進程分配資源,直到進程結束,收回資源。
線程是進程里真真跑的線路,真真執行的運算,每個進程有一個主線程。進程里可以開第二第三條新的執行線路,gcc 用 pthread_create(),VC++ 用 CreateThread(), 這就叫雙線程和多線程。進程是線程的容器,同一進程的線程共享它們進程的資源。線程里建的線程就是父子線程。
兩個或多個進程協同工作時,需要互相交換信息,有些情況下進程間交換的少量信息,有些情況下進程間交換大批信息。這就要通訊。通訊方式不止一種。管道就是一種。VC++ 用 CreatePipe() 函數建立。
管道的實質是一個共享文件,可藉助於文件系統的機制實現,創建、打開、關閉和讀寫.
一個進程正在使用某個管道寫入或讀出數據時,另一個進程就必須等待. 發送者和接收者雙方必須知道對方是否存在,如果對方已經不存在,就沒有必要再發送信息.,發送信息和接收信息之間要協調,當寫進程把一定數量的數據寫入管道,就去睡眠等待,直到讀進程取走數據後,把它喚醒。
VC++ 線程例子:
#include <windows.h>
#include <iostream.h>
DWORD WINAPI fun1(LPVOID lp);
DWORD WINAPI fun2(LPVOID lp);
int piao=500;
int main()
{
HANDLE pthread1,pthread2;
pthread1=CreateThread(0,0,fun1,0,0,0);
pthread2=CreateThread(0,0,fun2,0,0,0);
CloseHandle(pthread1);
CloseHandle(pthread2);
Sleep(3000);
return 0;
}
DWORD WINAPI fun1(LPVOID lp)
{
while(1)
{
if(piao>0)
cout<< "thread-1-"<< piao--<<endl;
else
break;
}
return 0;
}
DWORD WINAPI fun2(LPVOID lp)
{
while(1)
{
if(piao>0)
cout<<"thread-2-"<<piao--<<endl;
else
break;
}
return 0;
}
===================================
建管道函數原形:
BOOL CreatePipe(
PHANDLE hReadPipe, // read handle
PHANDLE hWritePipe, // write handle
LPSECURITY_ATTRIBUTES lpPipeAttributes, // security attributes
DWORD nSize // pipe size
);
I. 用C語言如何實現多線程同時運行的情況下,各個線程輸出不同的隨機數
1、使用pthread庫執行多線程,這個是Linux下的線程庫 Windows下應該有自己的API,不過這種東西一般還是以Linux為標准。pthread_create()創建一個線程,傳入橘態搭fun()的函數指針就行了。然後這個Beep()的需求要進行線程間通信,可以用共享內存的方法,設一個bool變數flag共享,然後beep的時候設為false,beep完設成true。fun()裡面每次看一下這個flag,是false的話就不做動作等下一閉啟秒,基本可以滿足需求。
2、常式:
#include<pthread.h>
#include<stdio.h>
#include<sys/time.h>
#include<string.h>
#defineMAX10
pthread_tthread[2];
pthread_mutex_tmut;
intnumber=0,i;
void*thread1()
{
printf("thread1:I'mthread1 ");
for(i=0;i<MAX;i++)
{
printf("thread1:number=%d ",number);
pthread_mutex_lock(&mut);
number++;
pthread_mutex_unlock(&mut);
sleep(2);
}
printf("thread1:主函數在等我完成任務嗎? ");
pthread_exit(NULL);
}
void*thread2()
{
printf("thread2:I'mthread2 ");
for(i=0;i<MAX;i++)
{
printf("thread2:number=%d ",number);
pthread_mutex_lock(&mut);
number++;
pthread_mutex_unlock(&mut);
sleep(3);
}
printf("thread2:主函數在等我完成任務嗎? ");
pthread_exit(NULL);
}
voidthread_create(void)
{
inttemp;
memset(&thread,0,sizeof(thread));//comment1
/*創建線程*/
if((temp=pthread_create(&thread[0],NULL,thread1,NULL))!=0)//comment2
printf("線程1創建失敗! ");
else
printf("線程1被創建 ");
if((temp=pthread_create(&thread[1],NULL,thread2,NULL))!=0)//comment3
printf("線程2創建失敗");
else
printf("線程2被創建 ");
}
voidthread_wait(void)
{
/*等待線程結束*/
if(thread[0]!=0){//comment4
pthread_join(thread[0],NULL);
printf("線程1已經結束 ");
}
if(thread[1]!=0){//comment5
pthread_join(thread[1],NULL);
printf("線程2已經結束 ");
}
}
intmain()
{
/*用默認屬性初始化互斥鎖圓拿*/
pthread_mutex_init(&mut,NULL);
printf("我是主函數哦,我正在創建線程,呵呵 ");
thread_create();
printf("我是主函數哦,我正在等待線程完成任務阿,呵呵 ");
thread_wait();
return0;
}
J. windows環境,多線程情況下,C語言向文件寫入數據。
①、對於你能寫這么長的問題描述,說明你很認真。
②、你的目的性較強,但是你也想有更加明確的目標,我可以給你講一下怎麼自己去尋找目標和路線以及怎樣學習。
③、計算機專業領域一共有幾個大方向,十幾個分支方向,而每個分支方向又有幾十個小方向,每一個方向的深入學習與熟練到一定火候都不是一朝一夕,互相之間也不是完全沒聯系的,但是你現在就應該選擇一個大方向並在其中的一個小方向內深入(為什麼要這么早就選擇具體的分支方向?後面說)。
④、這里列出計算機的幾個大方向(非編程開發類的我就不說了):
基本方向:
1、單片機、嵌入式方向
2、網路編程:涉及到伺服器程序、客戶端開發、腳本設計等。
3、系統編程:基礎API開發、桌面開發、系統程序開發、服務程序
4、圖形學:3D、2D、圖像識別、人臉識別
5、音頻:語音識別、音頻解碼、音頻軟體
6、編譯原理:編譯器設計、腳本解釋器、虛擬機、非自然語言翻譯系統
7、應用層開發:利用高層語言去開發表層應用
8、安全:反工程、病毒、反病毒、木馬、反木馬、軟體破解、軟體加殼
附加方向:
8、人工智慧:遺傳演算法、神經網路、灰色系統等等
9、游戲設計:各種游戲引擎設計以及業務邏輯設計等
⑤、基本方向是你一定要選的,附加方向只是基於基本方向的一些錦上添花,但是不管你怎麼選,最開始某些東西一定要深入而不是只是懂就夠(當然你對自己要求似乎不會很低),我把這個列出來:
數據結構:下面其他理論的基礎。
操作系統原理:理解操作系統的架構和細節,你才能對以後關於多線程、文件管理、內存管理、指令優先順序等有一個正確理解和運用。
編譯原理:能夠升華你對計算機編程語言的理解,對以後出現的各種編譯、解釋、兼容、移植、優化、並發與並行演算法等有一個深入理解。
資料庫系統原理:這個是進入公司都要會的,也是大型軟體開發的基礎。
軟體工程:這個是你能夠在經驗不足還能保證大項目正常完成的理論基礎。
網路技術:這個是必須學的,因為目前幾乎沒有一款裝幾率很高的軟體或者平台跟網路無關。
數學的話,主要是:離散數學、線性代數、高等數學、計算機圖形學、概率論
以上幾個基礎就是你成為一個融匯各個主要分支牛人必須學的(當然不是指理論,而是理論+實踐編碼能力)
⑥以上都是大的基礎,要一一攻破並深入學習,雖然網路時代計算機專業知識爆炸式的增長,但是以上幾個基礎掌握後,會發現,以後的什麼新的理論和技術都是基於這些大基礎,你就很容易理解了。
⑦我為什麼開頭不講你要具體學什麼怎麼順序學呢?因為那些技術你要掌握的話,根本可以自己解決,但是如果你由於興趣,沉迷於一些自己可見的小范圍技術的話,那麼畢業後雖然也能找到不錯的工作,薪水也可能高,但是不能成為一個大牛。
現在才開始講學習順序,雖然你說不要推薦書,不過我還是要用書來做順序。
C語言是可以寫很多核心和高級的東西,而不只是小東西,但是從你代碼來看,居然用到了 goto,我不是說你那些程序用到GOTO有什麼不好,而是一定要避免用GOTO,goto是錯誤之源,如果你有什麼內容非要用到goto才能寫到,說明你的編碼技巧還有不少提高空間。
你的學習順序應該是:
C:做一個超級馬里奧出來,並能夠讀取文本腳本來更新關卡。
C++:寫一個2D圖形引擎,封裝掉細節,實現面向對象設計和可復用設計,並且用到《設計模式》中提到的一些設計模式,這樣才能算對C++有一個很好的掌握。
MFC:MFC技術雖然近期已經冷下來了,但是你能熟練掌握它,才能證明你的C++OO技術夠純熟,嚴格證明你掌握了MFC很簡單,你只要用MFC做出一個殺毒引擎就差不多了。推薦的書有《深入淺出MFC》。
《Windows程序設計》:和MFC不同的是,用的是windows核心SDK,也就是API,這本書學完後,你才能從操作系統層面上算掌握了win32 平台下的機理(其實win64和win32大部分機理類似)。
C#:C#里集合了當代和前沿計算機科學里最先進的一些語法(雖然執行效率一直被人質疑),但是你學完C#並深入後,至少能夠算是對計算機語言有一個更加深刻的理解了。如何證明你C#學的不錯了?也很簡單,再次寫一個隨便什麼游戲,比如俄羅斯方塊。如果更加證明自己呢?用它寫一個P2P網路對戰游戲。
(如果你注意的話,會發現我說的學習順序都是沿著語言和某些技術的,為什麼呢?因為這些語言和技術涉及到特定的領域技術和計算機理論思想,比如學完了C#的話,就不單指學完了C#,而是把多種語言範式都學習了一遍,以及現代的程序開發思維(因為裡面用到了很多讓你一勞永逸的技術))
以上5個步驟都是基礎大步驟,要解決的話要沒1-2年應該不夠。
與此同時,要盡快選出文中你感興趣的方向作為3-5年的長期方向,不要擔心過早選擇分支方向會有什麼損失,因為計算機很多分支是相通的,只有你把分支方向深入進去,才能真正理解很多理論的實踐意義。並且一旦你在某個分支領域形成了較強的優勢(比如,到公司里只有你這方面最強),那麼你就是稀缺人才。
關於大方向的步驟就不說了,你主要就是要把我說的這幾個基礎步驟先解決,同時平時要注重大方向理論結合實際去編碼和開發。