实验三《并发程序》
并发程序1
学习使用Linux命令wc(1)
基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端
客户端传一个文本文件给服务器
服务器返加文本文件中的单词数
wc命令
Linux系统中的wc(Word Count)命令的功能为统计指定文件中的字节数、字数、行数,并将统计结果显示输出。- c 统计字节数,- l 统计行数,- w 统计字数。参考Linux下wc命令详解
在实现wc命令的过程中出现了如下问题:
- 对于字数的概念完整性问题,wc中对字数的定义是由空格字符区分开的最大字符串,而我的理解是由空格键隔开的字符串,导致我对字数的统计不准确。对于test1.txt文件,wc命令统计的字数是1576,而我的结果是3486.
- 输出的时候,注意格式控制,否则统计结果会混合在一起。
如图所示:
解决方法:字数统计中需要特别注意的是,当读到一个空格的时候,有两种情况:
1、前面一个字符也是空格(或回车),这时不能将字数加一。
2、前面一个字符不是空格,这时认为字数加一。
如何才能实现上面所说的区别呢?最自然的办法就是再找一个变量记录一下。
这里我通过inspace这个变量记录前一个字符的状态,如果前一个字符是空格或者回车,就将inspace置1,其他字符就置0;在读到一个空格时,判断inspace,当inspace为0时,才表示一个字结束,将字数w++。
修改后的核心代码如下:
while((t=fgetc(in))!=EOF)
{
if((t==' ')&&(inspace==0))
{
w++;
m++;
inspace=1;
}
else if(t=='\n')
{
l++;
m++;
inspace=1;
}
else{
m++;
inspace=0;
}
}
具体完整代码见码云
客户端和服务器文件传输
之前我们已经实现了,具体内容见我的另一篇博客。daytime服务器——客户端。
这里我们需要考虑的是如何传输文件。
最直接想到的办法就是将文件读入一个buffer然后传到客户端。
具体代码见码云,最终实现效果如下图。
并发程序2
使用多线程实现wc服务器并使用同步互斥机制保证计数正确,对比单线程版本的性能,并分析原因。
多线程互斥机制
线程就是运行在进程上下文中的逻辑流
一个进程里允许同时运行多个线程程序。线程由内核自动调度。每个线程都有自己的线程上下文。所有运行在一个进程里的线程共享该进程的整个虚拟空间。
信号量提供了一种很方便的方法来确保对共享变量的互斥访问。基本思想是将每个共享变量与一个信号量联系起来,然后用PV操作将相应临界区包围起来。
互斥锁适用于同时可用的资源是唯一的情况;信号量适用于同时可用的资源为多个的情况。
互斥锁机制主要包括以下基本函数:
● 互斥锁初始化:pthread_mutex_init()
● 互斥锁上锁:pthread_mutex_lock()
● 互斥锁判断上锁:pthread_mutex_trylock()
● 互斥锁解锁:pthread_mutex_unlock()
● 消除互斥锁:pthread_mutex_destroy()
信号量就是操作系统中多用到的PV原子操作,它广泛应用于进程或线程间的同步与互斥。信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。
Linux实现了Posix的无名信号量,主要用于线程间的互斥与同步。这里主要介绍几个常见函数:
● sem_init()用于创建一个信号量,并初始化它的值。
● sem_wait()和sem_trywait()都相当于P操作,在信号量>0时,它们能将信号量的值减1。两者的区别在于信号量<0时,sem_wait(0将会阻塞进程,而sem_trywait则会立即返回。
● sem_post()相当于V操作,它将信号量的值加1,同时发出信号来唤醒等待的进程。
● sem_getvalue()用于得到信号量的值。
● sem_destroy()用于删除信号量。
根据书上P695的例子(基于线程的并发服务器),参考我的另一篇博客并发的daytime服务器。