tcp/ip 多线程服务器端的实现(参考tcp/ip网络编程)

线程的切换比进程快的多,因为它不需要切换数据区和堆

共享数据区和堆可以用来交换信息


一、线程的创建

pthread_create()函数

#include<pthread.h>

int prthread_create(pthread * thread,const pthread_attr_t * attr,void *(*start_routine)(void *),void * arg)//成功是返回0

thread: 线程id

attr: 线程属性,一般为NULL

start_routine :调用函数的地址

arg:调用函数时传参数的地址

pthread_join()  等待指定线程结束后返回

#include<pthread.h>

int pthread_join(pthread_t thread,void ** status)//成功时返回0

thread:该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);
		else	
			pthread_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);//init
	int i;
	for(i=0;i<NUM_THREAD;i++)
	{
		if(i%2==0)
			pthread_create(&(thread_id[i]),NULL,thread_one,NULL);
		else	
			pthread_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);//destroy
	return 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);//init
	sem_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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值