tcp/ip 多线程服务器端的实现(参考tcp/ip网络编程)
来源:互联网 发布:suse linux 11 编辑:程序博客网 时间:2024/06/13 16:45
线程的切换比进程快的多,因为它不需要切换数据区和堆
共享数据区和堆可以用来交换信息
一、线程的创建
pthread_create()函数
#include<pthread.h>int prthread_create(pthread * thread,const pthread_attr_t * attr,void *(*start_routine)(void *),void * arg)//成功是返回0thread: 线程idattr: 线程属性,一般为NULLstart_routine :调用函数的地址arg:调用函数时传参数的地址
pthread_join() 等待指定线程结束后返回
#include<pthread.h>int pthread_join(pthread_t thread,void ** status)//成功时返回0thread:该id表示的线程终止后才从中返回status:线程返回值的指针地址
例子thread1.c:pthread_create pthread_join配合使用
#include <stdio.h>#include <unistd.h>#include <pthread.h>void * thread_main(void *arg){int k=*((int *)arg);int i;for(i=0;i<k;i++){sleep(1);printf("%d\n",i );}return NULL;}int main(int argc, char const *argv[]){pthread_t t_id;int thread_num=5;void *thr_return;if(pthread_create(&t_id,NULL,thread_main,(void *)&thread_num)<0){puts("pthread_creat() error");}pthread_join(t_id,&thr_return);printf("pthread return message %s\n",(char *)thr_return );return 0;}编译是加上:-lpthread
g++ -o pthread thread1.c -lpthread
运行结果:
0
1
2
3
4
pthread return message (null)
二、线程存在的问题
函数分为线程安全与非线程安全的,要使用系统提供函数的线程安全函数需要添加编译宏:-D_REENTRANT()
临界区:多个线程中这样的代码块:可能同时访问某一共享变量
如:int sum=0;是一个全局变量
线程a、b都要执行sum++;有可能在线程a中还没有完成这个动作就切换到了线程b中执行sum++,这将引起错乱!
例子thread2.c
#include <pthread.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#define NUM_THREAD 100//创建100个线程void * thread_one(void *);void * thread_two(void *);long long num=0;int main(){pthread_t thread_id[NUM_THREAD];int i;for(i=0;i<NUM_THREAD;i++){if(i%2==0)pthread_create(&(thread_id[i]),NULL,thread_one,NULL);elsepthread_create(&(thread_id[i]),NULL,thread_two,NULL);}for(i=0;i<NUM_THREAD;i++)pthread_join(thread_id[i],NULL);printf("return:%lld\n",num);return 0;}void *thread_one(void * arg){int i;for(i=0;i<500000;i++)num++;return NULL;}void *thread_two(void * arg){int i;for(i=0;i<500000;i++)num--;return NULL;}编译:gcc thread2.c -D_REENTRANT -o th2 -lpthread
运行4次的结果
return:2879406
return:2862240
return:2147264
return:1912373
本来的运行结果应该是0,下面我们来看如何解决?
三、线程同步
什么是同步:一个线程访问全局变量时,应该阻止其他线程的访问
需要同步的情况:
1、同时访问同一内存空间时发生的情况。
2、需要指定访问同一内存空间的线程的执行顺序的情况。
互斥量:
#include<pthread.h>int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t*attr);int pthread_mutex_destroy(pthread_mutex_t *mutex);int pthread_mutex_lock(pthread_mutex_t *mutex);/*临界区代码*/int pthread_mutex_unlock(pthread_mutex_t *mutex);以上函数成功时返回0;
mutex:互斥变量的地址
attr: 互斥量的属性,默认为NULL
一个例子看懂互斥量的使用:
例子thread3.c:
<pre name="code" class="cpp">#include <pthread.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#define NUM_THREAD 100//创建100个线程void * thread_one(void *);void * thread_two(void *);long long num=0;pthread_mutex_t mutex;//int main(){pthread_t thread_id[NUM_THREAD];pthread_mutex_init(&mutex,NULL);//initint i;for(i=0;i<NUM_THREAD;i++){if(i%2==0)pthread_create(&(thread_id[i]),NULL,thread_one,NULL);elsepthread_create(&(thread_id[i]),NULL,thread_two,NULL);}for(i=0;i<NUM_THREAD;i++)pthread_join(thread_id[i],NULL);printf("return:%lld\n",num);pthread_mutex_destroy(&mutex);//destroyreturn 0;}void *thread_one(void * arg){int i;pthread_mutex_lock(&mutex);//for(i=0;i<500000;i++)num++;pthread_mutex_unlock(&mutex)//;return NULL;}void *thread_two(void * arg){int i;for(i=0;i<500000;i++){pthread_mutex_lock(&mutex);//num--;pthread_mutex_unlock(&mutex);//}return NULL;}运行结果:return :0
因为thread_two要运行500000次lock、unlock
信号量:
信号量与互斥量极为相似(此处我们只使用01信号量)
#include<semaphore.h>int sem_init(sem_t *sem,int pshared,unsigned int value);int sem_destroy(sem_t *sem);int sem_post(sem_t *sem);//++/*临界区*/ int sem_wait(sem_t *sem);//--
以上函数成功时返回0
sem:信号量变量地址
pshared:0在本进程内部使用,其他值可以多个进程共享
value:信号量的初始值
例子thread4.c(读入一个数,求它与sum的和,将和存在sum中,循环5次)
#include <pthread.h>#include <semaphore.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#define NUM_THREAD 100//创建100个线程void * Read(void *);void * accu(void *);int num;sem_t sem_one;sem_t sem_two;int main(){pthread_t id1,id2;sem_init(&sem_one,0,0);//initsem_init(&sem_two,0,1);pthread_create(&id1,NULL,Read,NULL);pthread_create(&id2,NULL,accu,NULL);pthread_join(id1,NULL);pthread_join(id2,NULL);sem_destroy(&sem_one);sem_destroy(&sem_two);return 0;}void *Read(void * arg){int i;for(i=0;i<5;i++){sem_wait(&sem_two);scanf("%d",&num);sem_post(&sem_one);}return NULL;}void *accu(void * arg){int i,sum=0;for(i=0;i<5;i++){sem_wait(&sem_one);sum+=num;sem_post(&sem_two);}printf("sum = %d\n",sum);return NULL;}运行结果:
1
2
3
4
5
sum = 15
执行顺序依次为
sem_wait(&sem_two);0 sem_post(&sem_one);1 sem_wait(&sem_one);0 sem_post(&sem_two);1Read、accu 函数交替调用且开始调用Read
四、多线程并发服务器的实现
#include<pthread.h>int pthread_detach(pthread_t thread);
thread 要销毁的进程id
- tcp/ip 多线程服务器端的实现(参考tcp/ip网络编程)
- TCP/IP网络编程 基于Linux编程_4 --多线程服务器端的实现
- TCP IP网络编程1 简单的回声服务器端、客户端
- TCP/IP网络编程
- TCP/IP网络编程
- 《TCP/IP网络编程》
- TCP/IP网络编程
- TCP/IP网络编程
- TCP/IP网络参考模型
- TCP/IP网络编程 学习笔记_11 --多进程服务器端
- TCP/IP网络编程_hello world服务器端与客户端
- TCP/IP网络编程_echo回声服务器端与/客户端
- TCP/IP网络编程_计算器服务器端客户端
- TCP/IP编程实现
- 一种基于TCP/IP协议的网络编程模式(并发式多线程编程)
- linux网络编程练习---聊天室(TCP/IP实现)
- Java的网络编程(TCP/IP)
- 基于TCP/IP的网络编程步骤
- Android SplashActivity启动时黑屏的问题
- 如何成为优秀的驱动开发工程师
- C语言高级指针
- java.lang.ClassNotFoundException: Didn't find class "*****Activity" on path: /data/ap
- 路由跟踪工具:traceroute
- tcp/ip 多线程服务器端的实现(参考tcp/ip网络编程)
- Insight Properties
- 医学的常识
- java基础总结_04
- SVN导出增量包 ,并获取本地编译的class文件
- Exception in thread http-apr-8080-exec-
- 会计的四个基本前提
- Java String类
- java中String byte HexString的转换