linux线程编程--初识线程

线程
LWP:light weight process轻量级的进程,本质仍然是进程。
linux中进程非常的成熟,只是为了符合潮流硬生生的分化出了线程。
Linux中的线程实际上还是进程。

线程与进程关系:
进程 独立的地址空间,拥有PCB。
线程:也有PCB,但是没有独立的地址空间(共享)
区别:在于是否共享地址空间

 

 


linux下:
线程是最小的执行单位
进程是最小的分配资源单位,可以看做是只有一个线程的进程。
线程与进程创建的底层机制是一样的,调用的clone()。
从内核角度看进程和线程都是一样的,拥有不同的PCB,指向内存的三级页
表是一样的。
线程可以看做寄存器和栈的集合。
内核空间也有栈,主要用来保存寄存器的值(任务切换时)
进程可以蜕变为线程。
查看LWP号: ps -lF pid 查看指定线程的lwp号
线程号是CPU分配时间轮片的依据。

线程之间共享与非共享的东西:
共享:文件描述符表,每种信号的处理方式,当前工作目录,用户ID和组ID
,内存地址空间(.text/.data/.bss/.heap/.so)
非共享:线程ID,处理器现场和栈指针(内核栈),独立的栈空间(用户空
间),errno变量,信号屏蔽字,调度优先级。

优缺点:
有点:提高程序并发性,开销小,数据通信、共享数据方便。
缺点:函数库不稳定,编写调试困难,GDB不支持,对信号支持不好。
缺点不是硬伤,优点比较突出。

线程控制原语:
int pthread_create(pthread_t *restrict thread,const pthread_attr_t
*restrict attr,void*(func)(void*),void 8restrict arg)
pthread_t pthread_self()
void pthread_exit(void *value)
int pthread_join(pthread_t thread,void **value)
int pthread_detach(pthread_t thread)

线程属性及修改:

注意事项:

********************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <pthread.h>

void *thread_func(void *arg)
{
printf("In thread id=%lu,pid = %lu\n",pthread_self(),getpid());

printf("Will out thread.\n");

return NULL;
}

int main(int argc,char *argv[])
{
int ret;
pthread_t tid;

ret = pthread_create(&tid,NULL,&thread_func,0);
if(ret)
{
printf("Thread create failed.\n");
exit(1);
}

printf("In main id=%lu,pid = %lu\n",pthread_self(),getpid());
// sleep(1);

return 0;
}

********************************************************************************

执行结果:

 

我们看到线程没有输出。这是因为,进程结束后线程无法打印出来,所以需要打开主线程的sleep()函数,等待子线程输出之后,再结束。 

对于错误的判断可以使用

void *strerror(int  err);

 

创建多个线程:

******************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <pthread.h>

void *thread_func(void *arg)
{
int cn = (int)arg;
sleep(cn);
printf("In thread %d.\n",cn+1);

printf("Will out thread.\n");

return NULL;
}

int main(int argc,char *argv[])
{
int ret;
int i;
pthread_t tid;
for(i=0;i<5;i++)
{
ret = pthread_create(&tid,NULL,&thread_func,(void*)i);
if(ret)
{
printf("Thread create failed.\n");
exit(1);
}
}

sleep(5);
printf("In main id=%lu,pid = %lu\n",pthread_self(),getpid());


return 0;
}

******************************************************************************

执行结果:

 

       子线程中sleep()的作用是为了更加有序的打印信息。

        对于pthread_create()的最后一个参数传值不传地址,是因为在线程中取值的时候,该地址中的值可能已经改变了,这样打印出来的信息就不准确。

 

       通过定义一个全局变量,在子线程中修改全局变量,然后在主线程中再讲全局变量打印出来,就会发现全局变量被修改了,这样就可以证实线程共享全局变量。

 

NPTL: 线程库的版本。

   1、查看当前pthread库版本:在命令行执行  getconfGNU_LIBPTHREAD_VERSION

   2、NPTL实现机制{POSIX}

   3、使用线程库时gcc 指定-lpthread

 

使用线程库注意事项:

    1、主线程退出其它线程不退出,主线程映调用pthread_exit()

    2、要避免将是线程:

  pthread_join()

  pthread_detach()

  pthread_create() 指定分离属性。

  被join的线程可能在join函数返回之前就释放自己的所有资源,所以不应该返回被回收线程栈中的值。

 3、malloc和mmap申请的内存可以被其他线程释放。

    4、应避免在多线程模型中调用fork,除非马上exec,子进程中只有调用fork的线程存在,其他线程在子进程中军pthread_exit()

    5、信号的复杂语义很难和多线程共存,应避免在多线程引入信号。

 

  

posted @ 2020-08-13 06:58  houlianpi  阅读(117)  评论(0)    收藏  举报