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 = 558. 临界区问题示例
#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
843

被折叠的 条评论
为什么被折叠?



