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);1
Read、accu 函数交替调用且开始调用Read


四、多线程并发服务器的实现

#include<pthread.h>int pthread_detach(pthread_t thread);

thread  要销毁的进程id


0 0
原创粉丝点击