un第13天线程同步(信号量,条件变量)

 

===============线程同步(信号量,条件变量)==========

回顾:
一。线程:
 1。传参数(传个地址):pthread(&id,0,void*(*)(void*),void*);
使用地址传参,这说明了线程可接收任意类型大小的数据
 2。返回值(返回一个地址) so ,不能返回局部变量地址(代码区,全局区,堆区)
 
二。线程同步(即线程间的协调执行)
1。互斥量:本质是一个变量,一把锁。 保护临界资源的访问。保护方式就是所有访问临界资源的线程在临界区开始位置加锁,在临界区的结束位置解锁。  1。定义互斥量  2初始化(互斥量属性一把设置为NULL) 3.使用 4 删除
上课:
一。信号量(多线程中使用的一种计数器,是单一的,不是集合)
 1。可以加一减一的操作
 2。比进程中的信号量更轻量级,在线程中,那个在内核中管理。这个在线程中管理
 3。专门有个头文件:<semaphore.h>,这是线程信号量专有的头文件。<sys/sem.h>这是进程中的信号量
 4。sem_t类型 sem_init初始化函数 sem_wait获取一个信号量-1 sem_post释放一个信号量+1
 sem_destroy 删除信号量  sem_trywait 获取一个信号量时,不成功时直接返回,不阻塞
 sem_timedwait 获取不成功时阻塞一段时间,超时则返回  sem_getvalue
 5.互斥量可以解决的问题可以用信号量来解决,相反也可以。 说明他们两的功能通用。性质差不多
 6。信号量是非负整数
 
 sem_init(信号量变量,0在同一个进程中使用(非0在不同进程中使用),1信号量资源数初始化)//1个资源    如果信号量只有1个,那么相当于一把锁的功能。
 
二。
1。数据库的创建连接,非常耗时。所以如果等到需要一个连接的时候才去创建他的话,就会导致资源和时间的消耗(服务器在创建连接花费大量的时间),so 我们应该预先准备好一些已经创建好了的数据库连接,放入到数据库连接池中,只要已有请求过来,就从连接中去取得即可,非常的高效呢!这个池就是一个容器罢了。

三。条件变量(当某个条件满足时,让某个线程等待,否则,执行)
1.pthread_cond_t 类型    init   destroy wait 根据条件判断是否等待   signal唤醒一个正在等待的线程   broadcast把所有的线程都叫醒。

2。生产者  缓冲区  消费者 :防止生产与消费的速度不协调,所以要个缓冲区

下午:
变量:pthread_cond_t full;full里头有许多阻塞的线程。
1.初始化条件变量  1。用init函数 参数1是变量,参数2是0   2。用预定义宏赋值初始化
2。wait()参数1是变量指针,参数2是互斥量的指针; 如果满了就阻塞,同时释放互斥量的资源。
3。signal(&full);唤醒一个在这里阻塞的线程.

条件变量和互斥量,解决了消费者和生产者的问题。

条件变量相当于线程的等待队列。

先加锁在判断,判断之后又发现不行,又释放锁,在那里阻塞(wait).
使用while代替if来判度条件,这样就可以判段一个条件是否一直成立。否则if只能判断一次的成立。

补充:
线程同步终止
线程分离终止:pthread_detach(id);//设置线程为分离状态,不可以join
线程取消:线程可以被另外一个同进程的任意线程取消。进程的取消可以通过发信号来终止、取消。
  pthread_canel(*(int*)p);//把这个线程的id当作参数传入进来取消(是存在一点点延迟的,不会立即取消)。他会运行到他认为可以取消的地点才取消,所以会延迟一点点。除非设置了取消类型,这于可以设置为立即取消。
 2。拒绝取消:pthread_setcanclestate(int state,int* oldstate);
   state:有2个值,表示理会取消信息,不理会取消信号。PTHREAD_CANCLE_DISABLE
    PTHREAD_CANCLE_ENABLE
 3. 设置取消类型:pthread_setcancletype(int ytpe,int *lodtype)
  type:  DEFFERID延迟取消(这是默认状态)
     ASYNCHRONOUS立即取消
 4.线程属性:(thread_attr.c)
  属性值不能直接设置 :pthread_attr_t 是一个结构体,属性是一个结构体变量,所以我们要改变属性必须通过他提供的函数来改变.
 pthread_attr_t attr;//定义属性
 pthread_attr_init(&attr);//初始化一个空的属性
 pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//添加属性
 pthread_create(&id,&attr,task,0);
 pthread_join(id,0);//没有join到,因为属性设置了。呵呵
线程:用户线程和内核线程


网络编程
 他是基于socket(套接字)来网络通信;
 1。socket(插座) 套接字,你我要通信,你插入到socket1,我也插入到socket2,这样我们就能够通信了。至于这2个socket是怎么联系的都屏蔽了(不管):文件,网络,无限,有限都可以通信。
 2。要socket编程,就要用到<sys/socket.h> 和内部的一些函数等
  int socket(int domain,int type,int protocol);返回一个描述符
  这个函数可以创建一个socket.
   参数1:通信域(网络呢,文件呢):都已经固定了,我们选择相应的东西即可。老协议就不说了

   参数2:按照什么方式通信1。流方式(一个接着一个)2。数据报方式(分割成很多的块,到了目的地才重新组合)
   参数3:选择你要的通信协议:一般都指定为0,通信协议由第一二个参数已经确定了tcp流 udp报
   
 3.步骤:socketA.c
  1,准备socket:  int sid =socket(PF_UNIX,SOCK_DGRAM,0);//socket描述符
  if(sd==-1)perror(),exit(-1);
  2.准备通信地址 sockaddr虚地址:为了保持一致罢了。 结构体  2个成员1协议簇2地址
   实际上要使用以下这些地址:sockaddr是不可用的,只是文档产物。  
man un.h 本地通信的头文件,里面有本地通信的地址。
man in.h
  struct sockaddr_un addr;
  addr.sun_familyxxxxxxxxxxxxxxxxxxxx
  3。邦定/连接:bind(int sockfd,const struct sockaddr *my_addr,socklen_t adrlen)
     connect();与bind的参数一致,所以我们只需要修改一下函数名即可。
   1.描述符2地址3地址长度
  4。通信
   用读写文件的方式进行通信;依旧是用文件的read/write来读写,通信,因为啥都是文件嘛
   
  5。关闭socket
   close(sd);同文件一样关闭,因为他本身就是个文件。差!

其他:
socket包括网络通信,和本地通信。不仅仅是网络通信。   
ipv6用128位:据说可以给世界每个沙子分配一个ip号。
ipv4用32位
邦定的时候,会创建sock文件来进行通信。用ls来查看,是s类型的文件:sock是文件用于本地的进程间的通信
本地通信于网络通信没有很大的区别,socketC.c
 1.改协议 PF_INET网络
 2.改地址 <netinet/in.h> sockaddr_in  sin_familY=AF_INET;
 3.改端口号 addr.sin_port=htons(8888);//随便一个没有人用的端口号。
    
     inet_aton("192.168.180.53",&addr.sin_addr);
telnet 192.168.0.23IP ip可以找到一台计算机 23端口号 端口号可以找到一个进程
 
端口号:是个逻辑值0--65535,0~1024: 21 ftp; 32 telnet; 80 http;
每个进程会使用一个端口号,新进程去找一个为使用过的端口号。
 
 4.转换一些格式的函数在头文件<arpa/inet.h>中。比如:地址转换为32位的东东。inet_aton 
 端口号也要转(上面有) htonl计算机格式转成网络格式 ntohl网络格式转成计算机格式 

看ppt里面的理论东东。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值