UDP、线程、mutex锁(day15)

时间:2022-08-02 19:13:12
一、基于UDP的网络编程模型
服务器端
1、创建socket.
2、将fd和服务器的ip地址和端口号绑定
3、recvfrom阻塞等待接收客户端数据
4、业务处理
5、响应客户端


客户端:
1、创建socket
2、向服务器发送数据sendto
3、阻塞等待服务器的响应信息
4、处理响应信息
5、断开通讯

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd,void *buf,size_t len,\
    int flags,
        struct sockaddr *src_addr,\
     socklen_t *addrlen);
功能:从一个socket上接收消息
参数:
sockfd:指定socket。socket(2)的返回值
buf:存放消息的缓冲区地址
len:指定buf的最大尺寸
flags:0
src_addr:存放的是对面的地址
addrlen:是一个值-结果参数。src_addr的长度
返回值:
成功  返回接收到的字节数
-1  错误  errno被设置
0    对面down机

#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len,         int flags,
              const struct sockaddr *dest_addr,\
         socklen_t addrlen);

功能:在socket上发送消息
参数:
sockfd:指定socket
buf:存放数据的缓冲区首地址
len:buf中有效的字节数
flags:0
dest_addr:目标地址
addrlen:目标地址的长度
返回值:
-1  错误  errno被设置
成功  返回发送出去的字节数。

编写代码实现基于udp的网络通讯。
代码参见:
userv.c   uclie.c

172.30.3.93

网络通讯

二、线程的基础
线程   执行的基本单位,线程共享进程的资源
进程   进程是资源分配的基本单位

每个线程有自己的tid。thread_id
每个线程有自己私有的栈帧。

三、线程的创建
系统提供了函数pthread_create(3)用于创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread, 
        const pthread_attr_t *attr,
                void *(*start_routine) (void *),\
         void *arg);
功能:创建一个新的线程
参数:
thread:存放线程id的缓冲区。
attr:NULL   缺省属性
start_routine:线程的执行函数
arg:start_routine函数的唯一参数。
返回值:
0  成功
错误   错误码

Compile and link with -pthread.
void *(*start_routine) (void *)

举例说明   创建新的线程
代码参见  pthread_c.c

getpid(2)获取进程的pid。
pthread_self(3)来获取线程自己的tid。
#include <pthread.h>
pthread_t pthread_self(void);
功能:获取当前线程的id
参数:
void
返回值:
返回线程的id。

四、线程退出、汇合、分离
线程的退出
1、return和exit(3)的区别
return只是函数的返回,在线程处理函数中,只是代表了线程的结束。而exit(3)代表的是进程的结束。进程中的所有线程就终止了。

2、使用函数pthread_exit(3)来终止一个线程
#include <pthread.h>
void pthread_exit(void *retval);
功能:终止当前线程
参数:
retval:指定传递给另一个线程的值,那个线程调用pthread_join(3)接收这个值。

返回值:
不返回给调用者。
3、pthread_cancel(3)
#include <pthread.h>
int pthread_cancel(pthread_t thread);
功能:给线程发送取消请求
参数:
thread:指定了接收请求的线程id。

返回值:
0  成功
非0   错误码

注意:使用pthread_cancel终止的进程,在使用pthread_join(3)获取线程退出信息的时候,获取到的是PTHREAD_CANCELED。

线程的汇合
pthread_join(3)等待线程的汇合
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
功能:汇合一个终止的线程
参数:
thread:指定了等待汇合的线程的id
retval:
返回值:
成功   0
失败   返回错误码

举例说明  线程的退出和汇合
代码参见pthread_e.c

线程的分离
pthread_detach(3)
#include <pthread.h>
int pthread_detach(pthread_t thread);
功能:分离一个线程
参数:
thread:指定要分离的线程
返回值:
0  成功
非0   错误码

举例说明  线程的分离
代码参见 pthread_d.c

新建的线程和进程中已经存在的线程是异步的。
这些线程会对公共资源形成竞争。怎么解决竞争?
1、可重入函数
2、让异步的线程同步的访问共享资源。

五、线程同步  
条件变量    mutex锁    信号量
举例说明   多个线程异步访问共享资源(临界资源)
代码参见   count.c

使用mutex锁解决临界资源的问题
什么是mutex锁?
pthread_mutex_t 是一个类型   mutex锁类型

mutex所是一个互斥设备。
一个mutex锁类型的变量有两中状态
unlocked:不被任何线程拥有
locked:被一个线程拥有

一个mutex锁从来不能被两个线程同时拥有。
如果一个线程想拥有的mutex锁,被另外的线程占用。那么这个线程挂起执行,直到另外线程放弃才能得到。

对临界资源的访问要遵守三歩:
1、先获取mutex锁
2、访问临界资源
3、释放mutex锁

phtread_mutex_init(3)
#include <pthread.h>

静态初始化一个mutex锁
pthread_mutex_t  fastmutex=PTHREAD_MUTEX_INITIALIZER;

int  pthread_mutex_init(pthread_mutex_t *mutex,             const  pthread_mutexattr_t *mutexattr);
功能:初始化一个mutex锁
参数:
mutex:指定要初始化的mutex锁
mutexattr:NULL     默认
返回值:
0

int  pthread_mutex_lock(pthread_mutex_t *mutex);
功能:获取mutex锁,如果这个锁不被其他线程占有,立即返回,拥有了这把锁。将锁的状态改变为locked。
这把锁被其他线程占有。挂起线程,直到其他线程解锁为止。
参数:
mutex:指定了要获取的mutex锁
返回值:
非0  错误
0 成功


int  pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:获取mutex锁,在其他线程占有这个mutex锁的时候,非阻塞。立即返回,错误。EBUSY
参数:
mutex:指定要获取的mutex锁
返回值:
非0  错误
0 成功
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:解锁mutex
参数:
mutex:释放mutex锁
返回值:
非0  错误
0 成功
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:销毁mutex锁
参数:
mutex:指定要销毁的mutex锁
返回值:
非0  错误
0 成功

改进count.c。使用mutex锁让进程同步访问临界资源。
总结:
一、基于UDP的编程模型
二、线程的基础
三、线程的创建
四、线程的退出、汇合、分离
五、线程同步   mutex锁