什么是线程?
(1)在一个程序里的一个执行路线叫做线程。更准确的定义是:线程是一个进程内部的控制序列。
(2)根据运行环境和调度者的身份,线程可以分为内核线程和用户线程。内核线程:运行在内核空间,由内核来调度。用户线程:运行在用户空间,由线程库来调度。
(3)线程的实现方式:完全在用户空间实现(创建和调度线程无需内核的干预,速度相当快);完全由内核调度;双层调度(实现两种实现模式的混合体,不但不会消耗过多的资源,而且线程切换速度也比较快,同时可以充分利用多处理器的优势。
线程优缺点?
优点:
(1)创建新线程的代价比创建新进程小的多
(2)与进程相比,线程之间的切换需要操作系统做的工作要少很多
(4)能充分利用多处理器的可并行数量。
(5)计算密集型应用。
(6)I/O密集型应用,为了提高性能,将I/O操作重叠。
缺点:
(1)性能损失 线程不是越多越好,合适最好。
多线程之间有切换成本,如果切换的成本大于并行的成本,并行更好
(2)健壮性降低 线程之间是缺乏保护的。
(3)缺乏访问控制
(4)编程难度提高
线程和进程的区别?
(1)进程是具有独立功能的程序关于某个数据集合的一次运行活动。
可以申请和拥有系统资源,是一个动态的概念,是活动的实体。
线程基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)。
(2)通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源。在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。
(3)子进程和父进程拥有不同的代码和数据空间,而多个线程则共享数据空间。某进程内的线程在其它进程不可见。
(4)线程上下文切换比进程上下文切换要快得多
POSIX线程库:
与线程有关的函数构成了一个完整的系列,大多数以pthred开头。
(1)创建线程
实现:
查看线程信息:
[a@localhost thread]$ ps axu | grep mythread
a 3515 0.0 0.0 103252 828 pts/3 S+ 17:17 0:00 grep mythread
[a@localhost thread]$ ps -aL | head -n1
PID LWP TTY TIME CMD
(2)获得线程自身ID
pthread_t pthread_self(void);
结果:
[a@localhost thread]$ ./create
i am main thread!pid:3546,thread id:3355490048
i am thread 1!pid:3546,thread id:3355481856
i am main thread!pid:3546,thread id:3355490048
i am thread 1!pid:3546,thread id:3355481856
(3)线程终止
三种方式实现
(a)从线程函数return,这种方法对主线程不适用,从main函数return
相当于调用exit。(value_ptr所指向的单元内容存放的是thread线程函数的返回值)
(b)线程可以调用pthread_exit终止自己。(value_ptr所指向单元的内容是传给pthread_exit的参数)
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void *thread_run(void *arg)
{
printf("new thread running !pid: %d,thread id: %u\n",getpid(),pthread_self());
sleep(200);
pthread_exit((void*)123);
//exit(1);
// return (void*) 5;
}
int main()
{
pthread_t id;
pthread_create(&id,NULL,thread_run,NULL);
printf("main thread running !pid: %d,thread id: %u\n",getpid(),pthread_self());
sleep(1);
pthread_cancel(id);
void *code;
int ret =pthread_join(id,&code);
if(ret == 0)
{
printf("wait new thread success!,%d\n",(int)code);
}
return 0;
}
[a@localhost thread]$ ./thread
main thread running !pid: 7219,thread id: 2158917376
new thread running !pid: 7219,thread id: 2158909184
wait new thread success!,-1
[a@localhost thread]$
(c)一个线程可以调用pthread_cancel终止同一进程中的另一个线程。(value_ptr所指向单元的内容存放的是一个常数PTHREAD_CANCELED)
[a@localhost thread]$ ./thread
I am thread 1,id is:140022436087552
main thread run new thread ret:-1
[a@localhost thread]$ cat thread.c
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
void *thread_run(void *arg)
{
printf("I am %s,id is:%lu\n",(char*)arg,pthread_self());
//sleep(3);
pthread_exit((void*)123);
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,thread_run,"thread 1
//sleep(5);
pthread_cancel(tid);
void *ret;
pthread_join(tid,&ret);
printf("main thread run new thread ret:%d\n",(int)ret);
return 21;
}
线程创建后sleep5秒后,结果为:
[a@localhost thread]$ ./thread
I am thread 1,id is:140050701547264
main thread run new thread ret:123
[a@localhost thread]$
原因:主线程在sleep期间,线程已经退出,不是因为取消而结束,而因为退出而结束
分离线程
在任何一个时间点上,线程是可结合或者是分离的。默认情况下新创建的线程是可结合的。
一个可结合的线程能够被其它线程回收其资源和杀死。为避免内存泄漏,每个可结合的线程要么被显示地回收,即调用pthread_join;要么通过调用pthread_detach函数被分离。
一个分离的线程是不能被其它线程回收或杀死,它的存储器资源在它终止时由系统自动释放。
同步与互斥
同步强调顺序性和协同。一般都是在互斥的前提下,但有些场景也不需要互斥。
比如生活中这样的场景,门上挂着钥匙,一次只有一个人可以拿着钥匙开门进入,此时其他人在门外等待,门外的人按照一定的规则按顺序排队进门就是同步。
门内资源被某人占用,其他人在门外等待,这就是所谓的互斥。
互斥量:
也叫互斥锁,是实现同步的重要工具。在线程访问共享资源前对互斥量进行设置加锁(拿钥匙),在线程访问共享资源结束后释放互斥量解锁(交出钥匙)。
一个线程在占用资源时(钥匙),任何其他再试图申请同一份锁资源的线程,都会被阻塞。直到当前进程释放该锁资源。在互斥锁被释放时,所以因为该锁被阻塞的线程都会变成可运行状态,第一个变为运行的线程就可以对互斥量加锁,其它线程就会看到锁资源依然被占用,只能回去再次等待。
在这种方式下可以达到一个时刻只有一个线程可以向前执行,并且多线程时会按照一定的顺序进行协同。
相关函数:
(1)创建互斥量
动态分配:int pthread_mutex_init(pthread_mutex_t* restrict mutex,const pthread_mutexattr_t* restrict attr)
参数:mutex 要初始化的互斥量
attr NULL
静态分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
(2)加锁和解锁
加锁:int pthread_mutex_lock(pthread_mutex_t *mutex);
解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,失败返回错误号
(3)销毁互斥量
int pthread_mutex_destroy(pthread_mutex_t *mutex);
注意:
(a)使用PTHREAD_MUTEX_INITIALIZER初始化的互斥量不需要销毁。
(b)不要销毁一个已经加锁的互斥量
(c)已经销毁的互斥量,要确保后面不会有线程再尝试加锁。
结果:
thread 3 sells ticket:4
thread 2 sells ticket:3
thread 1 sells ticket:2
thread 1 sells ticket:1
thread 2 sells ticket:0
thread 3 sells ticket:-1
应用互斥量改进上面的售票系统:
结果: