文章目录
进程与线程实验一:创建进程基础版:创建父子线程 fork基础版:父子线程交替运行基础版:创建进程 文件写入练习版:创建线程 子读父阻塞 实验二:线程共享进程中的数据实验三:多线程实现单词统计工具
进程与线程
实验一:创建进程
1、学会通过基本的linux进程控制函数,由父进程创建子进程,并实现协同工作
2、创建两个进程,让子进程读取一个文件,父进程等待子进程读完文件后继续执行
注意:
fork创建的新进程被称为子进程,该函数被调用一次,但返回两次。两次返回的区别是:在子进程中的返回值是0,而在父进程中的返回值则是新进程的进程ID。
创建子进程,父进程哪个先运行根据系统调度且赋值父进程的内存空间。
vfork创建子进程,但子进程先运行且不复制父进程的内存空间
基础版:创建父子线程 fork
#include <unistd.h>#include <string.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>int main(void){ printf("pid:%d\n",getpid()); pid_t pid; pid = fork(); // 创建子进程 // 在fork之后会运行两个进程(父进程、子进程) if(pid <0){ perror("fork error"); } else if(pid>0){ // 父进程(在父进程中fork返回的是子进程的pid) printf("I am parent process pid is %d,ppid is %d,fork return is %d\n", getpid(),getppid(),pid); } else { // 子进程(在子进程中fork返回的是0) printf("I am child process pid is %d,ppid is %d,fork return is %d\n", getpid(),getppid(),pid); } printf("pid:%d\n",getpid()); sleep(1); // 睡眠 return 0;}
编译源文件:
root@ubuntu:/home/course/linux# gcc -o /home/course/linux/out/createThread /home/course/linux/createThread.c
-c
表示只编译(compile)源文件但不链接,会把.c或.cc的c源程序编译成目标文件,一般是.o文件。-o
用于指定输出(out)文件名。不用-o的话,一般会在当前文件夹下生成默认的a.out文件作为可执行程序。 root@ubuntu:/home/course/linux/# out/createThread # 直接运行
可以看到:
父进程(在父进程中fork返回的是子进程的pid)
子进程(在子进程中fork返回的是0)
返回顶部
基础版:父子线程交替运行
使用sleep()函数,实现线程的睡眠,每个进程运行后休眠一段时间,这时按照cpu的资源调度,使得其他进程运行。(若休眠时间短则会出现二次调用的情况)
#include <unistd.h>#include <string.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>int main(void){ printf("pid:%d\n",getpid()); pid_t pid; pid = fork(); // 创建子进程 // 在fork之后会运行两个进程(父进程、子进程) if(pid <0){ perror("fork error"); } else if(pid>0){ for(int i=0;i<10;i++){ // 父进程(在父进程中fork返回的是子进程的pid) printf("I am parent process pid is %d\n",getpid()); sleep(1); } } else { for(int i=0;i<10;i++){ // 子进程(在子进程中fork返回的是0) printf("I am child process pid is %d\n",getpid()); sleep(1); } } return 0;}
编译运行:
root@ubuntu:/home/course/linux# vi createThread1.croot@ubuntu:/home/course/linux# gcc -o /home/course/linux/out/createThread1 /home/course/linux/createThread1.c
返回顶部
基础版:创建进程 文件写入
父进程使用两种IO的形式进行文件的写入,默认当前路径下创建文件。注意区分缓存的概念以及文件的内容输出。
#include <unistd.h>#include <string.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>int main(void){ printf("pid:%d\n",getpid()); /*父进程调用写文件*/ FILE *fp =fopen("s.txt","w"); int fd = open("s_fd.txt",O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU|S_IRWXG); char *s = "hello world!"; ssize_t size = strlen(s)*sizeof(char); // 标准IO函数 - 带缓存 - 全缓存 fprintf(fp,"s:%s,pid:%d",s,getpid()); // 内核提供的IO系统 - 不带缓存 write(fd,s,size); pid_t pid; pid = fork(); // 创建子进程 // 在fork之后会运行两个进程(父进程、子进程) if(pid <0){ perror("fork error"); } else if(pid>0){ for(int i=0;i<10;i++){ // 父进程(在父进程中fork返回的是子进程的pid) printf("I am parent process pid is %d\n",getpid()); sleep(1); } } else { for(int i=0;i<10;i++){ // 子进程(在子进程中fork返回的是0) printf("I am child process pid is %d\n",getpid()); sleep(1); } } // 父子进程都要执行 - 写入各自缓存 fprintf(fp,"pid:%d",getpid()); return 0;}
可以看到编译正常运行;
并且在目录下新生成了 s_fd.txt、s.txt 文件,当我们查看文件内容的时候,会发现两个文件中的内容有偏差:
使用内核提供的IO系统 - 不带缓存,是直接将内容写入,而标准IO函数 - 带缓存,写的内容是:fprintf(fp,"s:%s,pid:%d",s,getpid());
,并且在最后的时候父子进程都要执行一次标准的IO,將各自的缓存内容写入到文件中去,所以会重复内容一次。
返回顶部
练习版:创建线程 子读父阻塞
实验说明:
学会通过基本的Linux进程控制函数,由父进程创建子进程,并实现协同工作。创建两个进程,让子进程读取一个文件,父进程等待子进程读完文件后继续执行。解决方案:
进程协同工作就是要协调好两个或两个以上的进程,使之安排好先后次序并依次执行,可以用wait()或者waitpid()函数来实现这一点。当只需要等待任一子进程运行结束时,可在父进程中调用wait()函数。若需要等待某一特定子进程的运行结果时,需调用waitpid()函数,它是非阻塞型函数。#include <unistd.h>#include <string.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include<sys/types.h>#include<sys/wait.h>#define COLMAX 1024 //每一个字符串的最大长度(列)#define ROWMAX 64 //字符串最大个数(行)/*本代码实现用子进程打开同目录下的s_fd.txt文件并且父进程输出内容*/int main(void) { int p_id = -1; //子进程创建失败 if ((p_id = fork()) == -1) { printf("Process_1 Create Error\n"); } else if (p_id == 0) { //子进程部分 printf("%d Process Start Work\n", getpid()); char text[ROWMAX][COLMAX] = {0}; FILE *fp = fopen("s_fd.txt", "r+");//打开文件 if (fp == NULL) { //打开文件失败 printf("Fail to open file!\n"); } else { int i = 0; while ((fscanf(fp, "%s", text[i])) != EOF) { printf("%s\n", text[i]); i++; sleep(1); //等待1s方便查看输出 } } fclose(fp); exit(0); } //父进程部分 waitpid(p_id, NULL, 0);//阻塞等待 printf("%d process is end\n", p_id); return 0;}
rse/linux# vi createThread3.croot@ubuntu:/home/course/linux# gcc -o /home/course/linux/out/createThread3 /home/course/linux/createThread3.c root@ubuntu:/home/course/linux# out/createThread3
运行结果:
返回顶部
实验二:线程共享进程中的数据
实验说明:
了解线程与进程之间的数据共享关系。创建一个线程,在线程中更改进程中的数。解决方案:
在进程中定义共享数据,在线程中直接引用并输出该数据。#include <unistd.h>#include <string.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include<sys/types.h>#include<sys/wait.h>static int sharedata=4; // 共享数据void *create(void *arg){ printf("new pthread...\n"); printf("sharedata data = %d \n",sharedata); sharedata = 3; return (void *)(0);}int main(void){ pthread_t mythread ; sharedata=5; // 修改变量值 int error = 0; error = pthread_create(&mythread,NULL,create,NULL); if(error){ printf("pthread_create is not created...\n"); return -1; } sleep(1); printf("pthread_create is ok...\n"); printf("And shared data = %d\n \n",sharedata); return 0;}
root@ubuntu:/home/course/linux# vi createThread4.croot@ubuntu:/home/course/linux# gcc -o /home/course/linux/out/createThread4 /home/course/linux/createThread4.c -l pthreadroot@ubuntu:/home/course/linux# out/createThread4
运行结果:
如有报错,参见:https://blog.csdn.net/u014470361/article/details/83214911
返回顶部
实验三:多线程实现单词统计工具
实验说明:
多线程实现单词统计工具。解决方案:
区分单词原则:
凡是一个非字母或数字的字符跟在字母或数字的后面,那么这个字母或数字就是单词的结尾。允许线程使用互斥锁来修改临界资源,确保线程间的同步与协作。如果两个线程需要安全地共享一个公共计数器,需要把公共计数器加锁。线程需要访问称为互斥锁的变量,它可以使线程间很好地合作,避免对于资源的访问冲突。 #include <stdio.h>#include <pthread.h>#include <ctype.h>#include <stdlib.h>#include <fcntl.h> pthread_mutex_t counter_clock=PTHREAD_MUTEX_INITIALIZER; int main(int ac,char *av[]){ void *count_words(void *); if(ac!=3){ printf("Usage:%s file1 file2\n",av[0]); exit(1); } /*分別以av[1]、av[2]作为参数,创建两个线程t1、t2,线程t1、t2进入等待状态,输出统计的单词总数*/ pthread_t tidp1,tidp2; int error1,error2; error1=pthread_create(&tidp1,NULL,count_words,av[1]); error2=pthread_create(&tidp2,NULL,count_words,av[2]); pthread_join(tidp1,NULL); pthread_join(tidp2,NULL); return 0;} void *count_words(void *f){ char *filename=(char *)f; FILE *fp; int c,prevc='\0'; int total_words=0; if((fp=fopen(filename,"r"))!=NULL){ while((c=getc(fp))!=EOF){ if(!isalnum(c) && isalnum(prevc)){ pthread_mutex_lock(&counter_clock); total_words++; pthread_mutex_unlock(&counter_clock); } prevc=c; } fclose(fp); printf("total_words=%d\n",total_words); }else{ perror(filename); } return NULL;}
创建两个包含英文单词的txt
文件:
root@ubuntu:/home/course/linux# vi createThread5.croot@ubuntu:/home/course/linux# gcc -o /home/course/linux/out/createThread5 /home/course/linux/createThread5.c -l pthreadroot@ubuntu:/home/course/linux# ./out/createThread5 ./a.txt ./b.txt total_words=5total_words=3
运行结果:
返回顶部