Linux系统下的C语言多线程开发
前言
本机为微软Surface pro4
,为64
位,所用操作系统为Windos 10
。本机虚拟机版本为Oracle VM VirtualBox 6.1.8
,所用操作系统是使用Ubuntu18.04
,。Ubuntu的虚拟硬盘设置为200G
,显存为128MB
,内存为4G
,CPU
2个,所用镜像源为清华大学软件镜像源。所使用linux
内核为linux-5.11.8
。
注意事项
(1)使用本博客中的指令时一定要采取对应自己电脑安装的Ubuntu
配置。
(2)我在Geany
中只创建了一个文件,使用注释来进行不同的程序编译运行。所以截图中运行的文件名都一样。
(3)实验二和实验三编译时如果编译器使用的Geany
时,尽量使用终端指令进行编译。
(4)当程序使用文件查看函数,所查看的文件必须与本.c文件在同一文件夹里面。
在Ubuntu下查看sched.h文件内的task_struct结构体
1、使用指令sudo su
登录Ubuntu,然后输入密码,获取超级用户权限。
2、使用指令cd /
跳转到根目录。(注:根目录为所有用户共享)
3、使用指令find -name sched.h
在根目录中寻找sched.h
文件。(注:图中红线所标注的即为我们所要查看的sched.h文件,大家Ubuntu下的内核安装路径不同,但是我们不同的系统中要查看的sched.h文件都有的路径为/include/linux/sched.h)
4、使用指令vim /home/xieyibo/桌面/linux-5.11.8/include/linux/sched.h
查看自己Ubuntu的sched.h文件。
(注:sched.h文件界面如下)
5、在sched.h文件内使用指令/task_struct
搜索结构体task_struct
。
(注:搜索第一次界面如下)
6、在sched.h文件内使用指令n
再次执行指令/task_struct
直到搜索结构体task_struct
。
(更多文件编辑指令可参考博客https://blog.youkuaiyun.com/APPDREAMER/article/details/115413594
)
(注:成功界面如下)
创建测试进程
1、使用指令cd 桌面
和touch test.txt
在桌面创建一个测试文件test.txt
。
(注:创建完成界面如下)
(注:测试文本内容如下)
The quick brown fox jumped over the lazy dog.It was so cool!
2、打开Geany程序,然后点击新建按钮,创建一个新文件。
(注:创建完成界面如下)
3、在新建的文件中书写程序。(注:程序如下)
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include<stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
int main(){
pid_t child,pr; //pit_d用于Linux下定义进程ID
child=fork(); //创建进程
//创建子进程
if((child==-1)) //如果创建失败
{
printf("fork error."); //打印“创建进程失败”提示信息
exit(1); //退出程序
}
else if(child==0) //子进程执行程序
{
char s[] = "test.txt";
//只读打开文件
int fd = open(s, O_RDONLY);
if(fd == -1) {
printf("error is %s\n", strerror(errno));
return;
}
//printf("sucess fd = %d\n", fd);
char buf[100];
memset(buf, 0, sizeof(buf));
//read返回0表示文件读取完毕
while(read(fd, buf, sizeof(buf) - 1) > 0) {
printf("%s\n", buf);
memset(buf, 0, sizeof(buf));
}
printf("%s\n", buf);
//别忘记关闭
close(fd);
}
else{ // 如果是父进程 */
pr=wait(NULL); // 在这里等待 */
printf("I catched a child process with pid of %d\n",pr);
}
return 0;
}
3.1–第3步中遇到的问题
问题一:在Ubuntu中无法写入中文。
问题原因:没有切换设置
解决办法:点击图中红线圈出的地方,然后将设置切换成汉语(intelligent Pinyin)。
(注:成功界面如下:)
3、先保存文件(注:文件保存时一定要记得加.c文件)到与测试文本test.txt
同一文件夹(目录)下,然后生成可执行文件并执行。(注:按如下图示中标明顺序点击按钮执行即可)
4、终端指令编译如图所示步骤执行即可。
(注:我把.c文件
和测试文本
均放入了文档
这个目录。大家按照自己的存放路径执行即可,以上终端指令只做参考即可)
线程共享进程中的数据
1、打开Geany程序,然后点击新建按钮,创建一个新文件。
(注:创建完成界面如下)
2、在新建的文件中书写程序。(注:程序如下)
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
static int shdata=4;
void *create(void *arg)
{
printf("new pthread...\n");
printf("shared data=%d\n",shdata);
return(void *)0;
}
int main(){
int res;
pthread_t tid;
res=pthread_create(&tid,NULL,create,NULL);
if(res)
{
printf("pthread_create is error!\n");
return -1;
}
sleep(2);
printf("pthread_create is succeed!\n");
return 0;
}
3、终端指令编译如图所示步骤执行即可。
多线程实现单词统计工具
1、在存放自己编写的.c程序的位置创建两个测试文件。(注:两个文档中所有的单词总共有27个)
2、打开Geany程序,然后点击新建按钮,创建一个新文件。
(注:创建完成界面如下)
3、在新建的文件中书写程序。(注:程序如下)
#include <stdio.h>
#include<pthread.h>
#include<ctype.h>
void *count_words(void*);
pthread_mutex_t counter_clock = PTHREAD_MUTEX_INITIALIZER;
static int number = 0;
int main(int ac,char *av[ ])
{
if(ac !=3)
{
printf("Usage:%s file1 filc2\n",av[0]);
return -1;
}
int res_1,res_2;
pthread_t tid_1,tid_2;
//分别以av[1]和av[2]作为参数,创建两个线程t1和t2
res_1 = pthread_create(&tid_1,NULL,count_words,av[1]); //创建线程,成功返回0,失败返回对应错误码
res_2 = pthread_create(&tid_2,NULL,count_words,av[2]);
if(res_1 != 0 && res_2 != 0)
{
printf("pthread_create is error..\n");
return -1;
}
//让线程t1和t2进入等待态
res_1 = pthread_join(tid_1,NULL); //使线程等待,成功返回0,失败返回对应错误码
res_2 = pthread_join(tid_2,NULL);
if(res_1 != 0 && res_2 != 0)
{
printf("pthread_join is failed...\n");
return -1;
}
/*打印统计出来的单词总数*/
printf("The total number of words output is %d\n",number);
return 0;
}
void *count_words(void *f)
{
char *filename = (char *)f;
FILE *fp; //文本指针
int c,prevc='\0';
if( (fp=fopen(filename,"r")) != NULL) //检测文件是否为空,文本不为空,执行以下程序
{
while((c=getc(fp)) != EOF) //持续从文本中读出字符,直到文本结束。
{
if(!isalnum(c) && isalnum(prevc)) //判断读出的字符不是字母和十进制数字
{
pthread_mutex_lock(&counter_clock); //互斥锁
number++;
pthread_mutex_unlock(&counter_clock); //打开互斥锁
}
prevc = c; //prevc被赋值为字符或者十进制数字
}
fclose(fp);
}
else
{
perror(filename); //打印错误信息
}
return NULL;
}
4、按如图所示使用终端指令编译执行即可。
4.1–第4步中可能遇到的问题。
问题一:编译时报错。
问题原因:pthread库不是Linux系统默认的库。
解决办法:使用指令gcc process2.c -lpthread -o process2
。
问题二:执行时报错。
问题原因:传给main()
函数的参数数量不对。
(注:使用终端是一个空格即为一个参数)
解决办法:使用指令./process2 test.txt test1.txt
。
(注:成功界面如下)