日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

c语言初始化字符串 函数 manment,[转载]3.09进程(C语言班最后一天的课程)

發(fā)布時(shí)間:2023/12/2 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言初始化字符串 函数 manment,[转载]3.09进程(C语言班最后一天的课程) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1,進(jìn)程:是容器,是內(nèi)存上的概念。線(xiàn)程是CPU的概念。

2,fork的作用是根據(jù)一個(gè)現(xiàn)有的進(jìn)程復(fù)制出一個(gè)新進(jìn)程,原來(lái)的進(jìn)程稱(chēng)為父進(jìn)程(Parents Process),新進(jìn)程稱(chēng)為子進(jìn)程(Child Process)。

系統(tǒng)中同時(shí)運(yùn)行著許多進(jìn)程,這些進(jìn)程都是從最初只有一個(gè)進(jìn)程開(kāi)始一個(gè)一個(gè)復(fù)制出來(lái)的。

分進(jìn)程函數(shù)fork(),用來(lái)開(kāi)辟子進(jìn)程。執(zhí)行fork()之后,會(huì)有兩個(gè)進(jìn)程,一個(gè)是原來(lái)的那個(gè),一個(gè)是新生成的子進(jìn)程。這兩個(gè)進(jìn)程都會(huì)執(zhí)行程序下面的代碼。pid = fork();pid得到的是返回子進(jìn)程的id,不是自己的id。

1.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(pid > 0){

printf("Parents!n");

}

if(0 == pid){

printf("Child!n");

}

printf("Hello world!n");

return 0;

}

3,先讓父進(jìn)程睡1秒,會(huì)先執(zhí)行子進(jìn)程。

2.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

printf("Child!n");

}else{

sleep(1);

printf("Parents!n");

}

return 0;

}

如果父進(jìn)程結(jié)束后,sleep(1);子進(jìn)程會(huì)打印到終端。

3.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

sleep(1);

printf("Son!n");

}else{

printf("Father!n");

}

return 0;

}

4,進(jìn)程號(hào):pid 。getppid()是得到當(dāng)前進(jìn)程父進(jìn)程的pid;getpid()是得到當(dāng)前進(jìn)程的pid。

如果子進(jìn)程getppid()時(shí),父進(jìn)程已經(jīng)死掉,子進(jìn)程就會(huì)被托管,那getppid()的值就為1。

所以父進(jìn)程要sleep(1),這樣子進(jìn)程getppid()時(shí),得到的就是此進(jìn)程父進(jìn)程的pid。

父進(jìn)程getppid()時(shí),得到的是終端的pid。

4.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

printf("Child!ngetppid=%d getpid=%d pid=%dn", getppid(),

getpid(), pid);

}else{

printf("Parents!ngetppid=%d getpid=%d pid=%dn", getppid(),

getpid(), pid);

sleep(1);

}

return 0;

}

5,ps查看進(jìn)程;

ps -jas 查看所有的進(jìn)程。

6,探討怎么讓父進(jìn)程知道子進(jìn)程結(jié)束?

exit(0)不會(huì)結(jié)束整個(gè)程序,只會(huì)結(jié)束一個(gè)進(jìn)程。wait(NULL)等待自己子進(jìn)程的結(jié)束。

父進(jìn)程執(zhí)行到wait()時(shí),會(huì)進(jìn)入休眠,子進(jìn)程結(jié)束時(shí),會(huì)發(fā)一個(gè)信號(hào),wait()會(huì)捕捉到這個(gè)信號(hào),以此來(lái)喚醒父進(jìn)程。

5.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

sleep(3);

printf("Child!n");

exit(0);

}

wait(NULL);

printf("Parents!n");

return 0;

}

7,探討父進(jìn)程與子進(jìn)程關(guān)于變量使用的問(wèn)題?

在fork()之后,會(huì)把原來(lái)的內(nèi)存完全復(fù)制一份,但不管怎么樣更改,都只會(huì)各改各的,互不干擾。

6.c

#include

#include

#include

#include

int main(void)

{

int a = 5;

int * p = &a;

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(pid > 0){

*p = 6;

printf("Parents:%dn", *p);

}else{

printf("Child:%dn", *p);

}

return 0;

}

8,怎么樣殺死進(jìn)程?

下面的程序是個(gè)死循環(huán),只能重新開(kāi)一個(gè)終端,執(zhí)行“kill -9 進(jìn)程號(hào)”。

如果執(zhí)行以下命令,一定要?jiǎng)h除交換文件:

$vi 5.c //進(jìn)入5.c 此進(jìn)程進(jìn)程號(hào)為3456

$Ctrl + z

//暫停當(dāng)前程序運(yùn)行

$kill -9 3456 //殺死vi 5.c,這個(gè)進(jìn)程

$fg

//回到剛暫停的程序中,會(huì)報(bào)錯(cuò),因?yàn)槟莻€(gè)進(jìn)程已經(jīng)被殺死了。要?jiǎng)h除那個(gè)交換文件才能執(zhí)行這個(gè)操作。

$ls -a//查看所有文件,能把交換文件查看出來(lái)。

$rm -fr ..5.c.swap. //刪除交換文件。

$fg

7.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

while(1){

printf("Child!n");

}

}else{

printf("Parents!n");

}

return 0;

}

9,exec族:用來(lái)代替原來(lái)進(jìn)程,執(zhí)行的時(shí)候完全代替,不會(huì)再回來(lái)。

#include

所需頭文件

(1)execl("/bin/ls", "ls", "-l",

NULL); 后面一定要加NULL,表示參數(shù)傳完了。

int

execl(const char *path, const char *arg0, ... )

8.c

#include

#include

#include

#include

int main(void)

{

int ret = execl("/bin/ls", "ls", "-l", NULL);

if(ret < 0){

perror("execl!n");

exit(0);

}

printf("Hello world!n");

return 0;

}

(2)

execlp已經(jīng)安裝過(guò)的程序,不需要寫(xiě)路徑。

int

execlp(const char *file, const char *arg0, ... );

9.c

#include

#include

#include

#include

int main(void)

{

int ret = execlp("ls", "ls", "-l", NULL);

if(ret < 0){

perror("execl!n");

exit(0);

}

printf("Hello world!n");

return 0;

}

(3)int execv(const char *path, char

*const argv[]);

int

execvp(const char *file, char *const argv[]);

10.c

#include

#include

#include

#include

int main(void)

{

char * buf[5] = {};

buf[0] = "ls";

buf[1] = "-l";

buf[2] = NULL;

int ret = execv("/bin/ls", buf);

// int ret =

execvp("ls", buf);

if(ret < 0){

perror("execv");

exit(0);

}

return 0;

}

10,whereis ls 查看ls的路徑。

11,-rwx-rwx-rwx:普通文件

drwx-rwx-rwx:d代表是一個(gè)文件夾

lrwx-rwx-rwx:l代表是一個(gè)快捷方式

12,cd是shell的內(nèi)置命令。如果輸入等于cd,則用chdir(),它并沒(méi)有fork()子進(jìn)程,是父進(jìn)程在執(zhí)行chdir()。

11.c

#include

#include

#include

int main(void)

{

chdir("dic");

//這個(gè)目錄要事先創(chuàng)建好。

mkdir("./ttt");

return 0;

}

如果用execlp(),會(huì)達(dá)不到想要的結(jié)果。

12.c

#include

#include

#include

#include

int main(void)

{

int ret = execlp("cd", "cd", "/", NULL);

if(ret < 0){

perror("execlp");

exit(0);

}

return 0;

}

13,一定要記住(固定格式):切割字符串函數(shù)strtok()

13.c

#include

#include

#include

#include

#define BUF 512

#define BUFF 10

int main(void)

{

char buf[BUF] = {};

ssize_t ret = read(0, buf, BUF);

int i = 0;

char * buff[BUFF] = {};

char * p = buf;

while(1){

p = strtok(p, " n");

if(!p)

break;

buff[i++] = p;

p = NULL;

}

for(i = 0; i < BUFF; i++){

if(NULL == buff[i])

break;

printf("%sn", buff[i]);

}

execvp(buff[0], buff);

return 0;

}

14,編寫(xiě)一個(gè)自己的終端

14.c

#include

#include

#include

#include

#define BUF 512

#define BUFF 10

int main(void)

{

char buf[BUF];

char * buff[BUFF];

char * p = buf;

int i = 0;

pid_t pid;

int ret = 0;

while(1){

write(1, "myshell$", 8);

memset(buf, 0,

BUF);

read(0, buf, BUF);

while(1){

p = strtok(p, "n ");

if(!p){

break;

}

buff[i++] = p;

p = NULL;

}

buff[i] = NULL;

if(strcmp(buff[0], "cd") == 0){

chdir(buff[1]);

continue;

}

pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}else if(pid == 0){

ret = execvp(buff[0], buff);

if(ret < 0){

perror("execvp");

exit(0);

}

}else{

wait(NULL);

}

}

return 0;

}

15,仔細(xì)探討fork()的用法。

15.c

#include

#include

#include

#include

int main(void)

{

pid_t pid;

char * message;

int n = 0;

pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

message = "This is the childn";

n = 6;

}else{

message = "This is the parentn";

n = 3;

}

for(;n > 0; n--){

printf("%s", message);

sleep(1);

}

return 0;

}

程序運(yùn)行順序如下:

(1)父進(jìn)程初始化。

(2)父進(jìn)程調(diào)用fork,這是一個(gè)系統(tǒng)調(diào)用,因此進(jìn)入內(nèi)核。

(3)內(nèi)核根據(jù)父進(jìn)程復(fù)制出一個(gè)子進(jìn)程,父進(jìn)程和子進(jìn)程的PCB信息相同,用戶(hù)態(tài)代碼和數(shù)據(jù)也相同。因此,子進(jìn)程現(xiàn)在的狀態(tài)和父進(jìn)程一樣,做完了初始化,剛調(diào)用了fork進(jìn)入內(nèi)核,還沒(méi)有從內(nèi)核返回。

(4)現(xiàn)在有兩個(gè)一模一樣的進(jìn)程看起來(lái)都調(diào)用了fork進(jìn)入內(nèi)核等待從內(nèi)核返回(實(shí)際上fork只調(diào)用了一次),系統(tǒng)中還有很多別的進(jìn)程也等待從內(nèi)核返回。是父進(jìn)程先返回還是子進(jìn)程先返回,還是這兩個(gè)進(jìn)程都等待,先去調(diào)度執(zhí)行別的進(jìn)程,這都不一定,取決于內(nèi)核的調(diào)度算法。

(5)如果某個(gè)時(shí)刻父進(jìn)程被調(diào)度執(zhí)行了,從內(nèi)核返回后就從fork函數(shù)返回,保存在變量pid中的返回值是子進(jìn)程的id,是一個(gè)大于0的整數(shù),因此執(zhí)行下面else分支,然后執(zhí)行for循環(huán),打印"This is parentn"三次之后終止。

(6)如果某個(gè)時(shí)刻子進(jìn)程被調(diào)度執(zhí)行了,從內(nèi)核返回后就從fork函數(shù)返回,保存在變量pid中的返回值是0,因此執(zhí)行下面的if(0 == pid)分支,然后執(zhí)行for循環(huán),打印"This is childn"六次這樣之后終止。fork調(diào)用把父進(jìn)程的數(shù)據(jù)復(fù)制一份給子進(jìn)程,但此后二者互不影響,在這個(gè)例子中,fork調(diào)用之后父進(jìn)程和子進(jìn)程的變量message和n被賦予不同的值,互不影響。

(7)父進(jìn)程每打印一條信息就睡眠1秒,這時(shí)內(nèi)核調(diào)度別的進(jìn)程執(zhí)行,在這1秒這么長(zhǎng)的間隙里(對(duì)于計(jì)算機(jī)來(lái)說(shuō)1秒很長(zhǎng)了)子進(jìn)程很有可能被調(diào)度到。同樣地,子進(jìn)程每打印一條信息就睡眠1秒,在這1秒期間父進(jìn)程也很有可能被調(diào)度到。所以程序運(yùn)行地結(jié)果基本上是父子進(jìn)程交替打印,但這也不一定的,取決于系統(tǒng)中其他進(jìn)程的運(yùn)行情況和內(nèi)核的調(diào)動(dòng)算法,如果系統(tǒng)中其他進(jìn)程非常繁忙則有可能觀(guān)察到不同的結(jié)果。

(8)這個(gè)程序是在Shell下運(yùn)行的,因此Shell進(jìn)程是父進(jìn)程的父進(jìn)程。父進(jìn)程運(yùn)行時(shí)Shell進(jìn)程處于等待狀態(tài),當(dāng)父進(jìn)程終止時(shí)Shell進(jìn)程認(rèn)為命令執(zhí)行結(jié)束了,于是打印Shell提示符,而事實(shí)上子進(jìn)程這時(shí)還沒(méi)結(jié)束,所以子進(jìn)程的消息打印到了Shell提示符后面。最后光標(biāo)停在This is the child的下一行,這時(shí)用戶(hù)仍然可以敲命令,即使命令不是緊跟在提示符后面,Shell也能正確讀取。

fork函數(shù):

(1)fork函數(shù)的特點(diǎn)"調(diào)用一次,返回兩次",在父進(jìn)程中調(diào)用一次,在父進(jìn)程和子進(jìn)程中各返回一次。一開(kāi)始是一個(gè)控制流程,調(diào)用fork之后發(fā)生了分叉,變成兩個(gè)控制流程,這也就是"fork"(分叉)這個(gè)名字的由來(lái)了。子進(jìn)程中fork的返回值是0,而父進(jìn)程中fork的返回值則是子進(jìn)程的id(從根本上說(shuō)fork是從內(nèi)核返回的,內(nèi)核自有辦法讓父進(jìn)程和子進(jìn)程返回不同的值),這樣當(dāng)fork函數(shù)返回后,程序員可以根據(jù)返回值的不同讓父進(jìn)程和子進(jìn)程執(zhí)行不同的代碼。

(2)fork的返回值這樣規(guī)定也是有道理的。fork在子進(jìn)程中返回0,子進(jìn)程仍可以調(diào)用getpid函數(shù)得到自己的進(jìn)程id,也可以調(diào)用getppid函數(shù)得到父進(jìn)程的id。在父進(jìn)程中用getpid可以得到自己的進(jìn)程id,然而要想得到子進(jìn)程的id,只有將fork的返回值記錄下來(lái),別無(wú)他法。

(3)fork的另一個(gè)特性是所有由父進(jìn)程打開(kāi)的描述符都被復(fù)制到子進(jìn)程中。父、子進(jìn)程中相同編號(hào)的文件描述符在內(nèi)核中指向同一個(gè)file結(jié)構(gòu)體,也就是說(shuō)file結(jié)構(gòu)體的引用計(jì)數(shù)要增加。

16,exec函數(shù)

用fork創(chuàng)建子進(jìn)程后執(zhí)行的是和父進(jìn)程相同的程序(但有可能執(zhí)行不同的代碼分支),子進(jìn)程往往要調(diào)用一種exec函數(shù)以執(zhí)行另一個(gè)程序。當(dāng)進(jìn)程調(diào)用一種exec函數(shù)時(shí),該進(jìn)程的用戶(hù)空間代碼和數(shù)據(jù)完全被新程序替換,從新程序的啟動(dòng)例程開(kāi)始執(zhí)行。調(diào)用exec并不創(chuàng)建新進(jìn)程,所以調(diào)用exec前后該進(jìn)程的id并未改變。

exec族

man

3 exec

頭文件:#include

int execl(const char *path, const char *arg0, ... );

int execlp(const char *file, const char *arg0, ... );

int execle(const char *path, const char *arg0, ...);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

int execvP(const char *file, const char *search_path, char *const

argv[]);

man 2 execve

int execve(const char *path, char *const argv[], char *const

envp[]);

這些函數(shù)如果調(diào)用成功則加載新的程序從啟動(dòng)代碼開(kāi)始執(zhí)行,不再返回,如果調(diào)用出錯(cuò)則返回-1,所以exec函數(shù)只有出錯(cuò)的返回值而沒(méi)有成功的返回值。

不帶p(表示path)的exec函數(shù)第一個(gè)參數(shù)必須是程序的相對(duì)路徑或絕對(duì)路徑,例如"/bin/ls"或"./a.out",而不能是"ls"或"a.out"。對(duì)于帶字母p的函數(shù):如果參數(shù)中包含/,則將其視為路徑名。否則視為不帶路徑的程序名,在PATH環(huán)境變量的目錄列表中搜索這個(gè)程序。

帶由字母l(表示list)的exec函數(shù)要求將新程序的每個(gè)命令行參數(shù)都作為一個(gè)參數(shù)傳給它,命令行參數(shù)的個(gè)數(shù)是可變的,因此函數(shù)原型中有…,…中的最有一個(gè)可變參數(shù)應(yīng)該是NULL,起sentinel的作用。

對(duì)于帶有字母v(表示vector)的函數(shù),則應(yīng)該先構(gòu)造一個(gè)指向各參數(shù)的指針數(shù)組,然后將該數(shù)組的首地址當(dāng)作參數(shù)傳給它,數(shù)組中的最后一個(gè)指針也應(yīng)該是NULL,就像main函數(shù)的argv參數(shù)或者環(huán)境變量一樣。

對(duì)于以e(envirnoment)結(jié)尾的exec函數(shù),可以把一份新的環(huán)境變量傳給它,其他exec函數(shù)仍使用當(dāng)前的環(huán)境變量表執(zhí)行新程序。

事實(shí)上,只有execve是真正的系統(tǒng)調(diào)用,其他五個(gè)函數(shù)最終都調(diào)用execve,所以execve在man手冊(cè)第2節(jié),其他函數(shù)在man手冊(cè)第3節(jié)。

總結(jié)

以上是生活随笔為你收集整理的c语言初始化字符串 函数 manment,[转载]3.09进程(C语言班最后一天的课程)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。