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、线程的继承性

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

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

       如果你需要显式的设置一个线程的调度策略或参数,那么你必须在设置之前将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 }               

 

 

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页