子進程編譯文件
1. 如何用命令行編譯chromium的子進程
點擊展開上圖中的chrome文件夾,選擇chrome解決方案,右鍵設置為啟動項目,然後直接F5(調試->開始調試)就可以啟動程序調試了。
如果想以其他的解決方案為啟動項目,可以直接右鍵設置就行。不過需要增加下面一步設置:右鍵打開想要設置的啟動項目的屬性
2. Mingw 如何編譯進程函數
MinGW用的是Windows的API來實現這些功能。網上去找這些函數的使用說明,模仿示例代碼,多試幾次
信號燈是啥……我只知道信號量,是說semaphore嗎?
CreateSemaphore創建信號量/CloseHandle關閉信號量/ReleaseSemaphore釋放信號量資源/WaitForSingleObject獲取一個信號量資源
CreateFileMapping創建共享內存對象/CloseHandle關閉共享內存對象/MapViewOfFile映射共享內存/UnmapViewOfFile取消映射共享內存
創建的對象和linux那一套函數不同,默認是不會繼承到CreateProcess創建的子進程里,你需要SetHandleInformation來允許它繼承。(對於有名字的這類對象,除了直接繼承、也可以在子進程里用名字打開)
內容太多太復雜,自己去搜。或者要書的話,推薦一本《Windows核心編程》
3. vs編譯報創建子進程出錯
問題處理:
選中當前工程->屬性->C/C++->常規->附加包含目錄->$(QTDIR)\include\QtANGLE。
問題現象:
error LNK1117: 選項「SUBSYSTEM:WINDOWS@QMAKE_SUBSYSTEM_SUFFIX@」中的語法錯誤 E:\Test-Project\EDC_Qt\EDCUIPro\LINK EDCUIPro
問題處理:
選中當前工程->屬性->C/C++->鏈接器->命令行,刪除其他選項 /SUBSYSTEM:WINDOWS%40QMAKE_SUBSYSTEM_SUFFIX%40
問題現象:
error LNK1112: 模塊計算機類型「X86」與目標計算機類型「x64」沖突
問題處理:
當前工程->屬性->平台->配置管理
問題現象:
error C2143: 語法錯誤 : 缺少「;」(在「*」的前面)
問題處理:
將報錯的那一行放到.cpp中定義,並初始化
問題現象:
error LNK2005: DllMain 已經在 dllmain.obj 中定義
問題處理:
一個項目裡面出來了兩個入口,這肯定是不允許的。刪掉預處理器_USRDLL。
問題現象:
error LNK1561: 必須定義入口點 E:\EDCProj\VAT_EDCDll\LINK VAT_EDCDll
問題處理:
項目屬性->項目默認值->配置類型,把.exe 改成 .Dll
問題現象:
無法找到 xx.exe調試信息
問題處理:
項目屬性->鏈接器->調試->生成調試信息,選擇「是(/DEBUG)」。注意:(.exe和.Dll)都要設置
問題現象:
error C2143: 語法錯誤 : 缺少「;」(在「*」的前面)
error C4430: 缺少類型說明符 - 假定為 int。注意: C++ 不支持默認 int
問題處理:
頭文件中加引用類的聲明
問題現象:
error LNK2001: 無法解析的外部符號 __imp___CrtDbgReportW
問題處理:
像這種情況,可以推測運用了錯誤的運行庫包。
在一程序中使用不同類型的運行時庫或使用調試和非調試版本的運行時庫,則將收到此鏈接錯誤。
例如,編譯一個文件以使用一種運行時庫,而編譯另一個文件以使用另一種運行時庫(例如單線程運行時庫對多線程運行時庫),試圖鏈接它們,則將得到此警告。應將所有源文件編譯為使用同一運行時庫。
在「配置屬性-->C/C++-->代碼生成-->運行時庫」中將「多線程(/MT)或者(/MD)」統一改為「多線程調試(/MTd)」
4. 一個Linux多進程編程
1 引言
對於沒有接觸過Unix/Linux操作系統的人來說,fork是最難理解的概念之一:它執行一次卻返回兩個值。fork函數是Unix系統最傑出的成就之一,它是七十年代UNIX早期的開發者經過長期在理論和實踐上的艱苦探索後取得的成果,一方面,它使操作系統在進程管理上付出了最小的代價,另一方面,又為程序員提供了一個簡潔明了的多進程方法。與DOS和早期的Windows不同,Unix/Linux系統是真正實現多任務操作的系統,可以說,不使用多進程編程,就不能算是真正的Linux環境下編程。
多線程程序設計的概念早在六十年代就被提出,但直到八十年代中期,Unix系統中才引入多線程機制,如今,由於自身的許多優點,多線程編程已經得到了廣泛的應用。
下面,我們將介紹在Linux下編寫多進程和多線程程序的一些初步知識。
2 多進程編程
什麼是一個進程?進程這個概念是針對系統而不是針對用戶的,對用戶來說,他面對的概念是程序。當用戶敲入命令執行一個程序的時候,對系統而言,它將啟動一個進程。但和程序不同的是,在這個進程中,系統可能需要再啟動一個或多個進程來完成獨立的多個任務。多進程編程的主要內容包括進程式控制制和進程間通信,在了解這些之前,我們先要簡單知道進程的結構。
2.1 Linux下進程的結構
Linux下一個進程在內存里有三部分的數據,就是"代碼段"、"堆棧段"和"數據段"。其實學過匯編語言的人一定知道,一般的CPU都有上述三種段寄存器,以方便操作系統的運行。這三個部分也是構成一個完整的執行序列的必要的部分。
"代碼段",顧名思義,就是存放了程序代碼的數據,假如機器中有數個進程運行相同的一個程序,那麼它們就可以使用相同的代碼段。"堆棧段"存放的就是子程序的返回地址、子程序的參數以及程序的局部變數。而數據段則存放程序的全局變數,常數以及動態數據分配的數據空間(比如用malloc之類的函數取得的空間)。這其中有許多細節問題,這里限於篇幅就不多介紹了。系統如果同時運行數個相同的程序,它們之間就不能使用同一個堆棧段和數據段。
2.2 Linux下的進程式控制制
在傳統的Unix環境下,有兩個基本的操作用於創建和修改進程:函數fork( )用來創建一個新的進程,該進程幾乎是當前進程的一個完全拷貝;函數族exec( )用來啟動另外的進程以取代當前運行的進程。Linux的進程式控制制和傳統的Unix進程式控制制基本一致,只在一些細節的地方有些區別,例如在Linux系統中調用vfork和fork完全相同,而在有些版本的Unix系統中,vfork調用有不同的功能。由於這些差別幾乎不影響我們大多數的編程,在這里我們不予考慮。
2.2.1 fork( )
fork在英文中是"分叉"的意思。為什麼取這個名字呢?因為一個進程在運行中,如果使用了fork,就產生了另一個進程,於是進程就"分叉"了,所以這個名字取得很形象。下面就看看如何具體使用fork,這段程序演示了使用fork的基本框架:
void main(){
int i;
if ( fork() == 0 ) {
/* 子進程程序 */
for ( i = 1; i <1000; i ++ ) printf("This is child process\n");
}
else {
/* 父進程程序*/
for ( i = 1; i <1000; i ++ ) printf("This is process process\n");
}
}
程序運行後,你就能看到屏幕上交替出現子進程與父進程各列印出的一千條信息了。如果程序還在運行中,你用ps命令就能看到系統中有兩個它在運行了。
那麼調用這個fork函數時發生了什麼呢?fork函數啟動一個新的進程,前面我們說過,這個進程幾乎是當前進程的一個拷貝:子進程和父進程使用相同的代碼段;子進程復制父進程的堆棧段和數據段。這樣,父進程的所有數據都可以留給子進程,但是,子進程一旦開始運行,雖然它繼承了父進程的一切數據,但實際上數據卻已經分開,相互之間不再有影響了,也就是說,它們之間不再共享任何數據了。它們再要交互信息時,只有通過進程間通信來實現,這將是我們下面的內容。既然它們如此相象,系統如何來區分它們呢?這是由函數的返回值來決定的。對於父進程,fork函數返回了子程序的進程號,而對於子程序,fork函數則返回零。在操作系統中,我們用ps函數就可以看到不同的進程號,對父進程而言,它的進程號是由比它更低層的系統調用賦予的,而對於子進程而言,它的進程號即是fork函數對父進程的返回值。在程序設計中,父進程和子進程都要調用函數fork()下面的代碼,而我們就是利用fork()函數對父子進程的不同返回值用if...else...語句來實現讓父子進程完成不同的功能,正如我們上面舉的例子一樣。我們看到,上面例子執行時兩條信息是交互無規則的列印出來的,這是父子進程獨立執行的結果,雖然我們的代碼似乎和串列的代碼沒有什麼區別。
讀者也許會問,如果一個大程序在運行中,它的數據段和堆棧都很大,一次fork就要復制一次,那麼fork的系統開銷不是很大嗎?其實UNIX自有其解決的辦法,大家知道,一般CPU都是以"頁"為單位來分配內存空間的,每一個頁都是實際物理內存的一個映像,象INTEL的CPU,其一頁在通常情況下是4086位元組大小,而無論是數據段還是堆棧段都是由許多"頁"構成的,fork函數復制這兩個段,只是"邏輯"上的,並非"物理"上的,也就是說,實際執行fork時,物理空間上兩個進程的數據段和堆棧段都還是共享著的,當有一個進程寫了某個數據時,這時兩個進程之間的數據才有了區別,系統就將有區別的"頁"從物理上也分開。系統在空間上的開銷就可以達到最小。
下面演示一個足以"搞死"Linux的小程序,其源代碼非常簡單:
void main()
{
for( ; ; ) fork();
}
這個程序什麼也不做,就是死循環地fork,其結果是程序不斷產生進程,而這些進程又不斷產生新的進程,很快,系統的進程就滿了,系統就被這么多不斷產生的進程"撐死了"。當然只要系統管理員預先給每個用戶設置可運行的最大進程數,這個惡意的程序就完成不了企圖了。
2.2.2 exec( )函數族
下面我們來看看一個進程如何來啟動另一個程序的執行。在Linux中要使用exec函數族。系統調用execve()對當前進程進行替換,替換者為一個指定的程序,其參數包括文件名(filename)、參數列表(argv)以及環境變數(envp)。exec函數族當然不止一個,但它們大致相同,在Linux中,它們分別是:execl,execlp,execle,execv,execve和execvp,下面我只以execlp為例,其它函數究竟與execlp有何區別,請通過manexec命令來了解它們的具體情況。
一個進程一旦調用exec類函數,它本身就"死亡"了,系統把代碼段替換成新的程序的代碼,廢棄原有的數據段和堆棧段,並為新程序分配新的數據段與堆棧段,唯一留下的,就是進程號,也就是說,對系統而言,還是同一個進程,不過已經是另一個程序了。(不過exec類函數中有的還允許繼承環境變數之類的信息。)
那麼如果我的程序想啟動另一程序的執行但自己仍想繼續運行的話,怎麼辦呢?那就是結合fork與exec的使用。下面一段代碼顯示如何啟動運行其它程序:
char command[256];
void main()
{
int rtn; /*子進程的返回數值*/
while(1) {
/* 從終端讀取要執行的命令 */
printf( ">" );
fgets( command, 256, stdin );
command[strlen(command)-1] = 0;
if ( fork() == 0 ) {
/* 子進程執行此命令 */
execlp( command, command );
/* 如果exec函數返回,表明沒有正常執行命令,列印錯誤信息*/
perror( command );
exit( errorno );
}
else {
/* 父進程, 等待子進程結束,並列印子進程的返回值 */
wait ( &rtn );
printf( " child process return %d\n",. rtn );
}
}
}
此程序從終端讀入命令並執行之,執行完成後,父進程繼續等待從終端讀入命令。熟悉DOS和WINDOWS系統調用的朋友一定知道DOS/WINDOWS也有exec類函數,其使用方法是類似的,但DOS/WINDOWS還有spawn類函數,因為DOS是單任務的系統,它只能將"父進程"駐留在機器內再執行"子進程",這就是spawn類的函數。WIN32已經是多任務的系統了,但還保留了spawn類函數,WIN32中實現spawn函數的方法同前述UNIX中的方法差不多,開設子進程後父進程等待子進程結束後才繼續運行。UNIX在其一開始就是多任務的系統,所以從核心角度上講不需要spawn類函數。
在這一節里,我們還要講講system()和popen()函數。system()函數先調用fork(),然後再調用exec()來執行用戶的登錄shell,通過它來查找可執行文件的命令並分析參數,最後它么使用wait()函數族之一來等待子進程的結束。函數popen()和函數system()相似,不同的是它調用pipe()函數創建一個管道,通過它來完成程序的標准輸入和標准輸出。這兩個函數是為那些不太勤快的程序員設計的,在效率和安全方面都有相當的缺陷,在可能的情況下,應該盡量避免。
2.3 Linux下的進程間通信
詳細的講述進程間通信在這里絕對是不可能的事情,而且筆者很難有信心說自己對這一部分內容的認識達到了什麼樣的地步,所以在這一節的開頭首先向大家推薦著名作者Richard Stevens的著名作品:《Advanced Programming in the UNIX Environment》,它的中文譯本《UNIX環境高級編程》已有機械工業出版社出版,原文精彩,譯文同樣地道,如果你的確對在Linux下編程有濃厚的興趣,那麼趕緊將這本書擺到你的書桌上或計算機旁邊來。說這么多實在是難抑心中的景仰之情,言歸正傳,在這一節里,我們將介紹進程間通信最最初步和最最簡單的一些知識和概念。
首先,進程間通信至少可以通過傳送打開文件來實現,不同的進程通過一個或多個文件來傳遞信息,事實上,在很多應用系統里,都使用了這種方法。但一般說來,進程間通信(IPC:InterProcess Communication)不包括這種似乎比較低級的通信方法。Unix系統中實現進程間通信的方法很多,而且不幸的是,極少方法能在所有的Unix系統中進行移植(唯一一種是半雙工的管道,這也是最原始的一種通信方式)。而Linux作為一種新興的操作系統,幾乎支持所有的Unix下常用的進程間通信方法:管道、消息隊列、共享內存、信號量、套介面等等。下面我們將逐一介紹。
2.3.1 管道
管道是進程間通信中最古老的方式,它包括無名管道和有名管道兩種,前者用於父進程和子進程間的通信,後者用於運行於同一台機器上的任意兩個進程間的通信。
無名管道由pipe()函數創建:
#include <unistd.h>
int pipe(int filedis[2]);
參數filedis返回兩個文件描述符:filedes[0]為讀而打開,filedes[1]為寫而打開。filedes[1]的輸出是filedes[0]的輸入。下面的例子示範了如何在父進程和子進程間實現通信。
#define INPUT 0
#define OUTPUT 1
void main() {
int file_descriptors[2];
/*定義子進程號 */
pid_t pid;
char buf[256];
int returned_count;
/*創建無名管道*/
pipe(file_descriptors);
/*創建子進程*/
if((pid = fork()) == -1) {
printf("Error in fork\n");
exit(1);
}
/*執行子進程*/
if(pid == 0) {
printf("in the spawned (child) process...\n");
/*子進程向父進程寫數據,關閉管道的讀端*/
close(file_descriptors[INPUT]);
write(file_descriptors[OUTPUT], "test data", strlen("test data"));
exit(0);
} else {
/*執行父進程*/
printf("in the spawning (parent) process...\n");
/*父進程從管道讀取子進程寫的數據,關閉管道的寫端*/
close(file_descriptors[OUTPUT]);
returned_count = read(file_descriptors[INPUT], buf, sizeof(buf));
printf("%d bytes of data received from spawned process: %s\n",
returned_count, buf);
}
}
在Linux系統下,有名管道可由兩種方式創建:命令行方式mknod系統調用和函數mkfifo。下面的兩種途徑都在當前目錄下生成了一個名為myfifo的有名管道:
方式一:mkfifo("myfifo","rw");
方式二:mknod myfifo p
生成了有名管道後,就可以使用一般的文件I/O函數如open、close、read、write等來對它進行操作。下面即是一個簡單的例子,假設我們已經創建了一個名為myfifo的有名管道。
/* 進程一:讀有名管道*/
#include <stdio.h>
#include <unistd.h>
void main() {
FILE * in_file;
int count = 1;
char buf[80];
in_file = fopen("mypipe", "r");
if (in_file == NULL) {
printf("Error in fdopen.\n");
exit(1);
}
while ((count = fread(buf, 1, 80, in_file)) > 0)
printf("received from pipe: %s\n", buf);
fclose(in_file);
}
/* 進程二:寫有名管道*/
#include <stdio.h>
#include <unistd.h>
void main() {
FILE * out_file;
int count = 1;
char buf[80];
out_file = fopen("mypipe", "w");
if (out_file == NULL) {
printf("Error opening pipe.");
exit(1);
}
sprintf(buf,"this is test data for the named pipe example\n");
fwrite(buf, 1, 80, out_file);
fclose(out_file);
}
2.3.2 消息隊列
消息隊列用於運行於同一台機器上的進程間通信,它和管道很相似,事實上,它是一種正逐漸被淘汰的通信方式,我們可以用流管道或者套介面的方式來取代它,所以,我們對此方式也不再解釋,也建議讀者忽略這種方式。
2.3.3 共享內存
共享內存是運行在同一台機器上的進程間通信最快的方式,因為數據不需要在不同的進程間復制。通常由一個進程創建一塊共享內存區,其餘進程對這塊內存區進行讀寫。得到共享內存有兩種方式:映射/dev/mem設備和內存映像文件。前一種方式不給系統帶來額外的開銷,但在現實中並不常用,因為它控制存取的將是實際的物理內存,在Linux系統下,這只有通過限制Linux系統存取的內存才可以做到,這當然不太實際。常用的方式是通過shmXXX函數族來實現利用共享內存進行存儲的。
首先要用的函數是shmget,它獲得一個共享存儲標識符。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size, int flag);
這個函數有點類似大家熟悉的malloc函數,系統按照請求分配size大小的內存用作共享內存。Linux系統內核中每個IPC結構都有的一個非負整數的標識符,這樣對一個消息隊列發送消息時只要引用標識符就可以了。這個標識符是內核由IPC結構的關鍵字得到的,這個關鍵字,就是上面第一個函數的key。數據類型key_t是在頭文件sys/types.h中定義的,它是一個長整形的數據。在我們後面的章節中,還會碰到這個關鍵字。
當共享內存創建後,其餘進程可以調用shmat()將其連接到自身的地址空間中。
void *shmat(int shmid, void *addr, int flag);
shmid為shmget函數返回的共享存儲標識符,addr和flag參數決定了以什麼方式來確定連接的地址,函數的返回值即是該進程數據段所連接的實際地址,進程可以對此進程進行讀寫操作。
使用共享存儲來實現進程間通信的注意點是對數據存取的同步,必須確保當一個進程去讀取數據時,它所想要的數據已經寫好了。通常,信號量被要來實現對共享存儲數據存取的同步,另外,可以通過使用shmctl函數設置共享存儲內存的某些標志位如SHM_LOCK、SHM_UNLOCK等來實現。
5. fortran主程序調用一個子程序,子程序又調用另一個子程序,如何編譯。
大致思路就是只要不把他們放在一個主程序內就OK了,放在同一個文件或者不同.f文件都是一樣的。對於第二個問題,回答也是可以的
比如說這樣的程序調用:
PROGRAM
MAIN
CALL
SUB1
END
SUBROUTINE
S
CALL
SUB2
END
SUBROUTINE
SUB2()
CALL
SUB3
END
SUBROUTINE
SUB3()
*********
END
這幾個子程序和主程序PROGRAM
MAIN可以放在同一個.f文件裡面編譯,也可以分別放置不同.f文件,編譯時效果一樣。
6. pid庫子程序編譯錯誤,未定義全局符號
你先檢查下是否導入了對應的庫文件,其次在看下是否導入了對應的頭文件。
針對上面出現的問題:操作步驟:1、先看下CIImage在哪個庫里,經查找得知在CoreImageframework裡面,查看二進制庫文件里沒有,所以要添加CoreImageframework二進制庫。
2、接著在使用的地方檢查是否導入了頭文件,結果是沒有,所以要導放到此錯誤已經解決。
7. 什麼是子進程和父進程
1、父進程
指已創建一個或多個子進程的進程。在UNIX里,除了進程0以外的所有進程都是由其他進程使用系統調用fork創建的,這里調用fork創建新進程的進程即為父進程,而相對應的為其創建出的進程則為子進程,因而除了進程0以外的進程都只有一個父進程,但一個進程可以有多個子進程。
2、子進程
指的是由另一進程(對應稱之為父進程)所創建的進程。子進程繼承了對應的父進程的大部分屬性,如文件描述符。在Unix中,子進程通常為系統調用fork的產物。在此情況下,子進程一開始就是父進程的副本,而在這之後,根據具體需要,子進程可以藉助exec調用來鏈式載入另一程序。

(7)子進程編譯文件擴展閱讀
父子進程之間的關系
1、關於資源
子進程得到的是除了代碼段是與父進程共享的意外,其他所有的都是得到父進程的一個副本,子進程的所有資源都繼承父進程,得到父進程資源的副本,既然為副本,也就是說,二者並不共享地址空間。兩個是單獨的進程,繼承了以後二者就沒有什麼關聯了,子進程單獨運行。
2、關於文件描述符
繼承父進程的文件描述符時,相當於調用了p函數,父子進程共享文件表項,即共同操作同一個文件,一個進程修改了文件,另一個進程也知道此文件被修改了。
8. 用c語言父進程創建子進程,通過文件進行交互,子進程每隔1秒向文件寫入數據,
你是想把對話框的資源腳本和類代碼加入單文檔工程中嗎?這比較麻煩,VC沒有自動化執行該任務的方法,你只能手動拷貝對話框的類文件,拷貝對話框工程的.rc資源腳本文件內的與對話框相關的腳本代碼到單文檔工程的.rc文件中,另外還要拷貝資源頭文件resource.h內的控制項ID預定義。
如果文檔和對話框的數據交互不多,可以不把兩個工程融合,分別編譯成各自的程序文件,在文檔的程序中通過創建子進程的方式打開對話框。這時數據交互比較麻煩,需要進程間通信。
9. bison: m4 子進程失敗: 沒有那個文件或目錄
參考:
prebuilts/misc/linux-x86/bison/bison: 沒有那個文件或目錄
android源碼編譯報錯:prebuilts/misc/linux-x86/bison/bison: 沒有這個文件或目錄
