Linux_多线程

对比进程与线程的区别

     (1)进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元

     (2)同一个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下文),一个进程至少包括一个线程。

     (3)进程的创建调用fork或者vfork,而线程的创建调用pthread_create,进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束

     (4)线程是轻两级的进程,它的创建和销毁所需要的时间比进程小很多,所有操作系统中的执行功能都是创建线程去完成的

     (5)线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源

     (6)线程有自己的私有属性TCB,线程id,寄存器、硬件上下文,而进程也有自己的私有属性进程控制块PCB,这些私有属性是不被共享的,用来标示一个进程或一个线程的标志

总结:

1, 在Linux下并不区分线程与进程,也就是说系统并不认为自己有线程这个东西,创建线程的函数pthread_create(pthread_t * p,NULL, (void*)func(void*arg) ,NULL); 是调用了POSIX的库函数,不是系统调用。也就是利用posix库函数模拟出来了线程。

2, 线程ID有两种:

    1>    放在线程PCB中的pid,供系统调用时使用(轻量级进程)

    2>    在创建线程时的返回型参数,pthread_t id,供编程时使用,

            如线程等待函数,pthread_join(pthread_t id ,  NULL);

            该函数用于等待进程并回收进程资源。

3,证明:同一进程内的多个线程公用同一块虚拟地址空间
答:

                 创建多个线程,去修改同一全局变量,最终每个进程得到的变量都一样。

                使用fork创建子进程,父子进程同时修改全局变量,最终得的值不一样,这是因为子进程独自拥有一份虚拟地址空

                间,在变量发生改变时,通过改变页表,完成写时拷贝。

4,为啥要有互斥

1> 多进程,多线程执行的先后顺序不同,切换的时机也不确定。

2> 多进程,多线程访问变量的动作不是原子的。

5,如何避免死锁
1> 短:临界区代码简短明了。

    2> 平:临界区代码逻辑清晰,无复杂的函数调用。
    3> 快:临界区代码执行速度快。

结线程属性

          线程属性结构如下:

typedef struct

{

   int                               detachstate;   线程的分离状态

   int                               schedpolicy;  线程调度策略

   structsched_param              schedparam;  线程的调度参数

   int                               inheritsched;  线程的继承性

   int                                scope;       线程的作用域

   size_t                           guardsize;   线程栈末尾的警戒缓冲区大小

   int                                stackaddr_set;

   void*                          stackaddr;   线程栈的位置

   size_t                           stacksize;    线程栈的大小

}pthread_attr_t;

1、线程的分离状态

   线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。

而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。所以如果我们在创建线程时就知道不需要了解线程的终止状态,则可以pthread_attr_t结构中的detachstate线程属性,让线程以分离状态启动。

2、线程的继承性

   继承性决定调度的参数是从创建的进程中继承还是使用在schedpolicy和schedparam属性中显式设置的调度信息。Pthreads不为inheritsched指定默认值,因此如果你关心线程的调度策略和参数,必须先设置该属性。

   继承性的可能值是PTHREAD_INHERIT_SCHED(表示新现成将继承创建线程的调度策略和参数)和PTHREAD_EXPLICIT_SCHED(表示使用在schedpolicy和schedparam属性中显式设置的调度策略和参数)。

   如果你需要显式的设置一个线程的调度策略或参数,那么你必须在设置之前将inheritsched属性设置为PTHREAD_EXPLICIT_SCHED.

线程的同步与互斥

1,为啥要有互斥

多进程,多线程执行的先后顺序不同,切换的时机也不确定。

多进程,多线程访问变量的动作不是原子的。

例如:i++ cpu完成时会有三步操作,任意切换会导致出错

2,为啥要有同步:

                    多进程,多线程执行的先后顺序不同,切换的时机也不确定。

                    想要不同的线程为我们完成具有顺序的部分任务,就必须是使其具有顺序。

使用gdb调试多线程

给临界资源加锁,保证原子性

#include<stdio.h>
  2 #include<pthread.h>
  3 #include<unistd.h>
  4 int count =0;
  5 pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
  6 void * thread_run(void*arg)
  7 {
  8   int i=0;
  9   while(i<50000000)
 10   {
 11  pthread_mutex_lock(&lock);                                                                        
 12     count++;
 13 
 14   pthread_mutex_unlock(&lock);
 15     i++;
 16   }
 17 
 18 
19   
 20   
 21 }
 22 int main ()
 23 {
 24   pthread_t tid1,tid2;
 25   pthread_create(&tid1,NULL,thread_run,NULL);
 26   pthread_create(&tid2,NULL,thread_run,NULL);
 27   pthread_join(tid1,NULL);
 28   pthread_join(tid2,NULL);
 29   printf(" res count is %d\n",count);
 30   return 0;
 31 }               


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值