一 进程与线程的区别:
进程:
进程是一个具有一定独立功能的程序的一次运行活动,同时也是资源分配的最小单元;
进程是程序执行时的一个实例,即它是程序已经执行到某种程度的数据结构的汇集。
从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。
Linux系统是一个多进程的系统,它的进程之间具有并行性、互不干扰等特点。
也就是说,每个进程都是一个独立的运行单位,拥有各自的权利和责任。其中,各个进程都运行在独立的虚拟地址空间,因此,即使一个进程发生异常,它也不会影响到系统中的其他进程。
线程:
线程是进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
一个进程由几个线程组成(拥有很多相对独立的执行流的用户程序共享应用程序的大部分数据结构),线程与同属一个进程的其他的线程共享进程所拥有的全部资源。
线程——程序执行的最小单位"
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。
线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。
二. 进程 VS线程
(1)和进程相比,它是一种非常“节俭”的多任务操作方式.在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。
运行于一个进程中的多个线程,它们之间使用相同的地址空间,而且线程间彼此切换所需的时间也远远小于进程间切换所需要的时间.据统计,一个进程的开销大约是一个线程开销的30倍左右。
(2)线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过进程间通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。
(3)除了以上所说的优点外,多线程程序作为一种多任务、并发的工作方式,有如下优点:
使多CPU系统更加有效.操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上.
改善程序结构.一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改.
三. 线程同步
进行多线程编程,因为无法知道哪个线程会在哪个时候对共享资源进行操作,因此让如何保护共享资源变得复杂,通过下面这些技术的使用,可以解决
线程之间对资源的竞争:
1 互斥量Mutex:
为什么需要互斥量:
Item * p =queue_list;
Queue_list=queue_list->next;
process_job(p);
free(p);
当线程1处理完Item *p=queue_list后,系统停止线程1的运行,改而运行线程2。线程2照样取出头节点,然后进行处理,最后释放了该节点。过了段时间,线程1重新得到运行。而这个时候,p所指向的节点已经被线程2释放掉,而线程1对此毫无知晓。他会接着运行process_job(p)。而这将导致无法预料的后果!
对于这种情况,系统给我们提供了互斥 量.线程在取出头节点前必须要等待互斥量,如果此时有其他线程已经获得该互斥量,那么该线程将会阻塞在这里.只有等到其他线程释放掉该互斥量后,该线程才有可能得到该互斥量。互斥量从本质上说就是一把锁, 提供对共享资源的保护访问
2 信号灯Semaphore
3 条件变量Conditions
四 .互斥量VS信号量
Mutex是一把钥匙,一个人拿了就可进入一个房间,出来的时候把钥匙交给队列的第一个。
Semaphore是一件可以容纳N人的房间,如果人不
满就可以进去,如果人满了,就要等待有人出来。
对于N=1的情况,称为binary semaphore。
Binary semaphore与Mutex的差异:
1. mutex要由获得锁的线程来释放(谁获得,谁释放)。而semaphore可以由其它线程释放
2. 初始状态可能不一样:mutex的初始值是1 ,semaphore的初始值可能是0(或者为1)
五 .编程示例
卖票演示:
/*****************************************************
> File name: sell_ticket.c
> Author: Mr.YUAN
> 日期: 2017-12-09 11:09
*****************************************************/
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
int ticket = 50;
pthread_mutex_t mutex;
void delay()
{
int i = rand()%10000;
int j;
while(i>0)
{
j = rand()%10000;
while(j > 0)
{
j--;
}
i--;
}
}
void *sale_ticket1(void *arg)
{
int cur_ticket;
while(1)
{
pthread_mutex_lock(&mutex);
cur_ticket = ticket;
if(cur_ticket <= 50)
{
pthread_cond_signal(&cond);
}
if(cur_ticket <= 0)
{
pthread_mutex_unlock(&mutex);
break;
}
printf("cur_ticket1 = %d\n",cur_ticket);
delay();
cur_ticket--;
ticket = cur_ticket;
pthread_mutex_unlock(&mutex);
}
}
void *sale_ticket2(void *arg)
{
int cur_ticket;
while(1)
{
pthread_mutex_lock(&mutex);
cur_ticket = ticket;
if(cur_ticket <= 0)
{
pthread_mutex_unlock(&mutex);
break;
}
printf("cur_ticket2 = %d\n",cur_ticket);
delay();
cur_ticket--;
ticket = cur_ticket;
pthread_mutex_unlock(&mutex);
}
}
int main()
{
int i;
int ret;
pthread_t tid[2] = {0};
ret = pthread_create(&tid[0],NULL,sale_ticket1,NULL);
if(0 != ret)
{
perror("pthread_create");
exit(1);
}
ret = pthread_create(&tid[1],NULL,sale_ticket2,NULL);
if(0 != ret)
{
perror("pthread_create");
exit(1);
}
/*for(i = 0;i < 5;i++)
{
ret = pthread_join(tid[i],NULL);
if(0 == ret)
{
perror("pthread_join");
exit(1);
}
pthread_mutex_destroy(&mutex);
}*/
pthread_join(tid[0],NULL);
pthread_join(tid[1],NULL);
return 0;
}