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

来源:互联网 发布:范剑青 知乎 编辑:程序博客网 时间:2024/05/17 06:25

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:等待的线程IDstatus:保存线程的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 -lpthreadalex@alex-VirtualBox:~/Share/Test/tcpip$ ./a.outsum = 55

8. 临界区问题示例

#include <stdio.h>#include <pthread.h>#include <unistd.h>#include <stdlib.h>#define NUM_THREAD100void * thread_inc(void *arg);void * thread_des(void *arg);long long num = 0;//bit64int 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);elsepthread_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 -lpthreadalex@alex-VirtualBox:~/Share/Test/tcpip$ ./a.outresult = 4289148349alex@alex-VirtualBox:~/Share/Test/tcpip$ ./a.outresult = -4307619450






0 0
原创粉丝点击