学习笔记7

第四章 并发编程

4.1 并行计算导论

Linux 环境中有很多应用程序和很多进程,其中最重要的是客户端网络/服务器。 多进程服务器是指当客户端发出请求时,服务器使用子进程来处理客户端的请求。 父进程继续等待来自其他客户端的请求。 这种方法的优点是服务器可以在客户端请求时管理客户端,特别是在交互式客户端/服务器系统中。 对于 TCP 服务器,客户端和服务器之间的连接可能不会立即关闭。 客户端发送数据后可以关闭连接。 在此期间,服务器端进程被阻塞,操作系统可能会设置其他计划。 此时的客户服务流程。 与循环服务器相比,该服务的性能得到了显着提高。

并行算法与计算环境:

并行计算是提高计算机系统计算速度和处理能力的一种有效手段。它的基本思想是用多个处理器来协同求解同一问题,即将被求解的问题分解成若干个部分,各部分均由一个独立的处理机来并行计算。并行计算系统既可以是专门设计的、含有多个处理器的超级计算机,也可以是以某种方式互连的若干台独立计算机构成的集群。 

多线程并发服务器

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

函数功能: 主函数,用进程建立一个TCP Echo Server

int main(int argc, char *argv[])

{

unsigned short port = 8080; // 本地端口

//1.创建tcp套接字

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

if(sockfd < 0)

{

perror("socket");

exit(-1);

}

//配置本地网络信息

struct sockaddr_in my_addr;

bzero(&my_addr, sizeof(my_addr)); // 清空

my_addr.sin_family = AF_INET; // IPv4

my_addr.sin_port = htons(port); // 端口

my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip

//2.绑定

int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));

if( err_log != 0)

{

perror("binding");

close(sockfd);

exit(-1);

}

//3.监听,套接字变被动

err_log = listen(sockfd, 10);

if(err_log != 0)

{

perror("listen");

close(sockfd);

exit(-1);

}

while(1) //主进程 循环等待客户端的连接

{

char cli_ip[INET_ADDRSTRLEN] = {0};

struct sockaddr_in client_addr;

socklen_t cliaddr_len = sizeof(client_addr);

// 取出客户端已完成的连接

int connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);

if(connfd < 0)

{

perror("accept");

close(sockfd);

exit(-1);

}

pid_t pid = fork();

if(pid < 0){

perror("fork");

_exit(-1);

}else if(0 == pid){ //子进程 接收客户端的信息,并发还给客户端

/*关闭不需要的套接字可节省系统资源,

同时可避免父子进程共享这些套接字

可能带来的不可预计的后果

*/

close(sockfd); // 关闭监听套接字,这个套接字是从父进程继承过来

char recv_buf[1024] = {0};

int recv_len = 0;

// 打印客户端的 ip 和端口

memset(cli_ip, 0, sizeof(cli_ip)); // 清空

inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);

printf("----------------------------------------------\n");

printf("client ip=%s,port=%d\n", cli_ip,ntohs(client_addr.sin_port));

// 接收数据

while( (recv_len = recv(connfd, recv_buf, sizeof(recv_buf), 0)) > 0 )

{

printf("recv_buf: %s\n", recv_buf); // 打印数据

send(connfd, recv_buf, recv_len, 0); // 给客户端回数据

}

printf("client_port %d closed!\n", ntohs(client_addr.sin_port));

close(connfd); //关闭已连接套接字

exit(0);

}

else if(pid > 0){ // 父进程

close(connfd); //关闭已连接套接字

}

}
close(sockfd);

return 0;

}

线程管理函数:

线程:线程标识

进程ID在整个系统中是唯一的
线程ID只在它所属的进程环境中有效
pthread_t类型通常用结构来表示
不能把它作为整数处理
Linux使用无符号长整数表示
为了移植,使用函数来比较线程ID

一、线程函数:成功则返回0,出错则返回错误编号

1 线程创建

int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, void *(*start_rtn)(void *), void *arg);

2 线程终止

void pthread_exit(void *rval_ptr);

3 线程等待:只能用于等待非分离线程

int pthread_join(pthread_t thread, void **rval_ptr);

4 线程取消

int pthread_cancel(pthread_t tid);

5 线程分离:使得线程终止时其资源立即被系统回收,而非分离状态则需要pthread_join来释放资源

int pthread_detach(pthread_t tid); 

6 获取线程ID

pthread_t pthread_self(void); //返回调用线程的线程ID

 条件变量:作为锁,互斥量仅用于确保线程只能互斥地访问临界区中的共享数据对象。条件变量提供了一种线程协作的方法。在Pthread中,使用类型pthread_cond_t来声明条件变量,而且必须在使用前进行初始化。与互斥量一样,条件变量也可以通过两种方法进行初始化。静态方法。

posted @ 2021-10-31 18:08  zzy188  阅读(11)  评论(0编辑  收藏  举报