第三十七章 POSIX线程(一)
POSIX线程库相关介绍
与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都有“pthread_”开头
要使用这些函数库,都需要加入头文件“<pthread.h>”, 链接的时候需要链接“-lpthread”
pthread_create
功能:
创建一个线程
原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
参数:
thread : 返回线程ID
attr : 设置线程属性,为NULL时表示使用默认属性
start_routine : 是个函数地址,线程启动后要执行的函数
arg : 传给线程启动函数的参数
返回值:
成功 :0
失败 : 返回错误码
pthread_exit
功能:
线程终止
原型:
void pthread_exit(void *retval);
参数:
retval :retval不要指向一个局部变量
返回值:
无返回值,跟进程一样,线程结束的时候无法返回到它的调用者(自身)
pthread_join
功能:
等待线程结束
原型:
int pthread_join(pthread_t thread, void **retval);
参数:
thread :线程ID
retval : 它指向一个指针,指向线程的返回值
返回值:
成功 : 0
失败 : 返回错误码
pthread_detach
功能:
分离线程
原型:
int pthread_detach(pthread_t thread);
参数:
thread :线程ID
返回值:
成功 : 0
失败 : 返回错误码
pthread_self
功能:
返回线程的ID
原型:
int pthread_self(void);
返回值:
总是成功,返回调用此函数的线程ID
pthread_cancle
功能:
取消一个执行中的线程
原型:
int pthread_cancel(pthread_t thread);
参数:
thread : 线程ID
返回值:
成功 : 0
失败 : 返回错误码
错误检查
- 传统的一些函数是,成功返回0, 失败返回-1,并且对全局变量errno赋值以指示错误
- pthread函数出错时不会设置全局变量errno(而大部分其它POSIX函数会这样做)。而是将错误代码通过返回值返回
- pthread同样也提供了线程内的errno变量,以支持其它使用errno的代码。对于pthread函数的错误设置,建议通过返回值判定,因为读取返回值要比读取线程内的errno变量的开销更小
进程线程对比
属性 | 进程 | 线程 |
---|---|---|
ID | pid_t | pthread_t |
创建 | fork | pthread_create |
等待 | waitpid | pthread_join |
僵尸 | waitpid | pthread_join、pthread_detach |
退出(自杀) | exit,return | pthread_exit,return |
他杀 | kill | pthread_cancel |
用线程实现回射客户端、服务器端
pserver.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
void do_service(int conn)
{
char recvbuf[1024] = {0};
while(1)
{
memset(recvbuf,0,sizeof(recvbuf));
int ret = read(conn,recvbuf,sizeof(recvbuf));
if(ret == 0)
{
printf("client close\n");
break;
}
else if(ret == -1)
ERR_EXIT("read");
fputs(recvbuf,stdout);
write(conn,recvbuf,ret);
}
}
void* thread_routine(void *arg)
{
pthread_detach(pthread_self());
// 使用取地址的方式获取
//int conn = *((int*)arg);
// 使用强制转换的方式获取
// int conn = (int)arg;
// 使用取地址的方式获取,释放空间
int conn = *((int*)arg);
free(arg);
do_service(conn);
printf("exit thread %lu ...\n",pthread_self());
return NULL;
}
int main(void)
{
int listenfd;
if((listenfd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
ERR_EXIT("socket");
struct sockaddr_in serv_addr;
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5188);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
// inet_aton("127.0.0.1",&serv_addr.sin_addr);
int on = 1;
if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,&on,sizeof(on)) < 0)
ERR_EXIT("setsockopt");
if(bind(listenfd, (struct sockaddr*)(&serv_addr), sizeof(serv_addr)) < 0)
ERR_EXIT("bind");
if(listen(listenfd, SOMAXCONN) < 0)
ERR_EXIT("listen");
struct sockaddr_in cli_addr;
socklen_t cli_len = sizeof(cli_addr);
int conn;
while(1)
{
if((conn = accept(listenfd, (struct sockaddr *)(&cli_addr), &cli_len)) < 0)
ERR_EXIT("accept");
printf("ip : %s port : %d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));
pthread_t tid;
int ret;
// 使用这种方式存在一定的问题,因为是&conn,如果accept返回后,thread_routine还没有来得及处理上一个conn,conn将被改变,导致上一次连接无法处理
// 最好不要使用指针传递,应使用值传递;
//if( (ret = pthread_create(&tid, NULL, thread_routine, (void*)&conn)) != 0 )
//使用这种方式,将int类型装换成无类型指针,int是4个字节,指针也是4个字节;但是这种做法是不可移植的,不同的操作系统,指针所占的字节数不一样
// if( (ret = pthread_create(&tid, NULL, thread_routine, (void*)conn)) != 0 )
//申请一块单独的内存放conn,取出后释放掉
int *p = malloc(sizeof(int));
*p = conn;
if( (ret = pthread_create(&tid, NULL, thread_routine, p)) != 0 )
{
fprintf(stderr, "pthread_create : %s\n", strerror(ret));
exit(EXIT_FAILURE);
}
}
return 0;
}
pclient.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
void handler(int sig)
{
printf("recv a sig :%d\n",sig);
exit(EXIT_SUCCESS);
}
int main(void)
{
int sock;
// socket(PF_INET,SOCK_STREAM,0);
if((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
ERR_EXIT("socket");
struct sockaddr_in serv_addr;
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5188);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0 )
ERR_EXIT("connect");
pid_t pid;
pid = fork();
if(pid < 0)
ERR_EXIT("fork");
if(pid == 0)
{
char recvbuf[1024] = {0};
while(1)
{
memset(recvbuf,0,sizeof(recvbuf));
int ret = read(sock,recvbuf,sizeof(recvbuf));
if (ret == -1)
ERR_EXIT("read");
else if(ret == 0)
{
printf("peer close\n");
break;
}
fputs(recvbuf,stdout);
}
close(sock);
kill(getppid(),SIGUSR1);
}
else
{
signal(SIGUSR1,handler);
char sendbuf[1024] = {0};
while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)
{
write(sock,sendbuf,strlen(sendbuf));
memset(sendbuf,0,sizeof(sendbuf));
}
close(sock);
}
return 0;
}
第三十七章 POSIX线程(一)的更多相关文章
- “全栈2019”Java多线程第三十七章:如何让等待的线程无法被中断
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- 程序员编程艺术第三十六~三十七章、搜索智能提示suggestion,附近点搜索
第三十六~三十七章.搜索智能提示suggestion,附近地点搜索 作者:July.致谢:caopengcs.胡果果.时间:二零一三年九月七日. 题记 写博的近三年,整理了太多太多的笔试面试题,如微软 ...
- Gradle 1.12用户指南翻译——第三十七章. OSGi 插件
本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- “全栈2019”Java第三十七章:类与字段
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- 第三十八章 POSIX线程(二)
线程属性 初始化与销毁属性 int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t * ...
- 第三十七章 springboot+docker(手动部署)
一.下载centos镜像 docker pull hub.c.163.com/library/centos:latest docker tag containId centos:7 docker ru ...
- 三十七、Linux 线程——线程清理和控制函数、进程和线程启动方式比较、线程的状态转换
37.1 线程清理和控制函数 #include <pthread.h> void pthread_cleanup_push(void (* rtn)(void *), void *arg) ...
- 【第三十七章】 springboot+docker(手动部署)
一.下载centos镜像 docker pull hub.c.163.com/library/centos:latest docker tag containId centos:7 docker ru ...
- SpringBoot | 第三十七章:集成Jasypt实现配置项加密
前言 近期在进行项目安全方面评审时,质量管理部门有提出需要对配置文件中的敏高文件进行加密处理,避免了信息泄露问题.想想前段时间某公司上传github时,把相应的生产数据库明文密码也一并上传了,导致了相 ...
随机推荐
- .net core 3.0 Signalr - 05 使用jwt将用户跟signalr关联
Signalr是以Group.Connect为核心来进行推送,比如,给某个组.某个连接来推送,但实际场景中,核心应该是某个组.某个人:然而一个人可以对应多个连接(浏览器多个tab页):本节就来介绍下自 ...
- 漫谈 GOF 设计模式在 Spring 框架中的实现
原文地址:梁桂钊的博客 博客地址:http://blog.720ui.com 欢迎关注公众号:「服务端思维」.一群同频者,一起成长,一起精进,打破认知的局限性. 漫谈 GOF 设计模式在 Spring ...
- 【solved】must have one register DataBase alias named `default`
beego在初始化MySQL数据库时报错处理 1.报错提示: ... [ORM]2019/10/11 08:42:52 register db Ping `default`, dial tcp 192 ...
- 《构建之法》MSF&需求分析
第七章 MSF MSF基本原则 推动信息共享与沟通 为共同的远景而工作 充分授权和信任 各司其职,对项目共同负责 交付增量的价值 保持敏捷,预期和适应变化 投资质量 学习所有的经验 与顾客合作 MSF ...
- bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html 一.初始化世界以及模型 /// 冲突配置包含内存的默认设置,冲突设置. ...
- Java 多线程爬虫及分布式爬虫架构探索
这是 Java 爬虫系列博文的第五篇,在上一篇 Java 爬虫服务器被屏蔽,不要慌,咱们换一台服务器 中,我们简单的聊反爬虫策略和反反爬虫方法,主要针对的是 IP 被封及其对应办法.前面几篇文章我们把 ...
- 02-11 RANSAC算法线性回归(波斯顿房价预测)
目录 RANSAC算法线性回归(波斯顿房价预测) 一.RANSAC算法流程 二.导入模块 三.获取数据 四.训练模型 五.可视化 更新.更全的<机器学习>的更新网站,更有python.go ...
- 03-01 K-Means聚类算法
目录 K-Means聚类算法 一.K-Means聚类算法学习目标 二.K-Means聚类算法详解 2.1 K-Means聚类算法原理 2.2 K-Means聚类算法和KNN 三.传统的K-Means聚 ...
- Kafka 介绍
Apache Kafka是一个分布式流式平台. 流平台有三个关键的能力: 发布和订阅记录流,类似于消息队列或企业消息传递系统. 使用容错耐用的方式存储记录流. 记录产生时处理数据. Kafka主要是用 ...
- LeetCode 300. Longest Increasing Subsequence最长上升子序列 (C++/Java)
题目: Given an unsorted array of integers, find the length of longest increasing subsequence. Example: ...