2021-04-04 Linux系统下的C语言多线程开发

本文档详细介绍了在Ubuntu环境下使用C语言进行多线程编程的步骤,包括查看内核头文件、创建进程、线程共享数据以及实现单词统计工具。涉及到的工具有Geany、终端指令及pthread库的使用,并给出了可能出现的问题及解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux系统下的C语言多线程开发

前言
本机为微软Surface pro4,为64位,所用操作系统为Windos 10。本机虚拟机版本为Oracle VM VirtualBox 6.1.8,所用操作系统是使用Ubuntu18.04,。Ubuntu的虚拟硬盘设置为200G,显存为128MB,内存为4GCPU2个,所用镜像源为清华大学软件镜像源。所使用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
(注:成功界面如下)
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值