18.1 多线程服务器端的实现1 —— 线程概念

1. Web服务器的发展迫使UNIX系列操作系统开始重视线程,Web服务器进程需要向多个客户端提供服务,因此逐渐舍弃进程,而用效率更高的线程。

2. 多进程模型的缺点:

a. 创建进程的过程需要大的开销;

b. 进程间通信需要用到IPC技术;

c. 经常发生“上下文切换Context Switching”,时间很长,很致命:进程A切换到进程B时,要将进程A信息移出内存,并读入进程B信息。


多线程(轻量级进程)的优点:

a. 线程的创建和上下文切换比进程更快;

b. 线程间通信无需特殊技术。


3. 进程VS线程

a. 每个进程都有自己的数据区、heap、stack,进程间相互独立。

线程间共享数据区和heap。

b. 进程:在操作系统构成单独执行流的单位;

线程:在进程构成单独执行流的单位;



4. 线程创建pthread_create

POSIX标准:Portable Operating System Interface for Computer Environment适用于计算机环境的可移植操作系统接口

#include <pthread.h>

int pthread_create(pthread_t * restrict thread, const pthread_attr_t restrict attr, void *(*start_routine)(void *), void * restrict arg)

成功返回0,失败其他值

thread:保存新创建进程ID的变量地址值
attr:用于传递线程属性的参数,NULL表示默认
start_routine:线程的执行流函数指针
arg:第三个参数函数指针的参数信息

5. 进程/线程等待pthread_join

int pthread_join(pthread_t thread, void **status)

成功返回0,失败其他值

thread:等待的线程ID
status:保存线程的main函数返回值的指针变量地址值

6. 可在临界区critical section内调用的函数

临界区:多个线程同时调用函数时可能产生问题,这类函数内部存在临界区。临界区中至少存在一条这类代码。

线程安全函数:被多个线程同时调用时不会引发问题;线程安全函数的名称以_r后缀 //与临界区无关,安全函数也可能有临界区

非线程安全函数:被同时调用时会引发问题。

编译使用_r的函数方法:声明头文件前定义_REENTRANT,也可以# gcc -D_REENTRANT mythread.c -o mthread -lpthread


7. 示例:工作worker线程模型

代码只说模型应用,里面存在临界区问题。


#include <stdio.h>
#include <pthread.h>
void * thread_summation(void *arg);

int sum = 0;

int main(int argc, char *argv[]){
	pthread_t id_t1,id_t2;
	int range1[] = {1,5};
	int range2[] = {6,10};

	pthread_create(&id_t1,NULL,thread_summation,(void *)range1);
	pthread_create(&id_t2,NULL,thread_summation,(void *)range2);

	pthread_join(id_t1,NULL);
	pthread_join(id_t2,NULL);
	
	printf("sum = %d\n",sum);
	return 0;
}

void * thread_summation(void *arg){
	int start = ((int *)arg)[0];
	int end = ((int *)arg)[1];

	while(start <= end){
		sum += start;
		start++;
	}

	return NULL;
}
执行结果:

alex@alex-VirtualBox:~/Share/Test/tcpip$ gcc thread3.c -D_REENTRANT -lpthread
alex@alex-VirtualBox:~/Share/Test/tcpip$ ./a.out
sum = 55

8. 临界区问题示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>

#define NUM_THREAD	100


void * thread_inc(void *arg);
void * thread_des(void *arg);

long long num = 0;	//bit64

int main(int argc, char *argv[]){
	pthread_t thread_id[NUM_THREAD];
	int i;

	for(i=0;i<NUM_THREAD;i++){
		if(i%2)
			pthread_create(&thread_id[i],NULL,thread_inc,NULL);
		else
			pthread_create(&thread_id[i],NULL,thread_des,NULL);
	}
	for(i=0;i<NUM_THREAD;i++)
		pthread_join(thread_id[i],NULL);
	
	printf("result = %lld\n",num);
	return 0;
}

void * thread_inc(void *arg){
	int i;

	for(i=0;i<50000000;i++){
		num += 1;
	}

	return NULL;
}

void * thread_des(void *arg){
	int i;

	for(i=0;i<50000000;i++){
		num -= 1;
	}

	return NULL;
}

执行结果:执行结果非0,而且每次执行结果都不一样!

alex@alex-VirtualBox:~/Share/Test/tcpip$ gcc thread4.c -D_REENTRANT -lpthread
alex@alex-VirtualBox:~/Share/Test/tcpip$ ./a.out
result = 4289148349
alex@alex-VirtualBox:~/Share/Test/tcpip$ ./a.out
result = -4307619450






评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值