1、查看进程或者线程

查看进程:

ps -aux|grep  a.out

ps -ef|grep  a.out

top 

查看线程:

ps -xH|grep  a.out

top -H

1、创建线程

在Linux下,采用pthread_create函数来创建一个新的线程,函数声明:

函数声明:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

参数thread为为指向线程标识符的地址。

参数attr用于设置线程属性,一般为空,表示使用默认属性。

参数start_routine是线程运行函数的地址,填函数名就可以了。

参数arg是线程运行函数的参数。新创建的线程从start_routine函数的地址开始运行,该函数只有一个无类型指针参数arg。若要想向start_routine传递多个参数,可以将多个参数放在一个结构体中,然后把结构体的地址作为arg参数传入,但是要非常慎重,程序员一般不会这么做。

在编译时注意加上-lpthread参数,以调用静态链接库。因为pthread并非Linux系统的默认库。

2、线程的终止

 如果进程中的任一线程调用了exit,则整个进程会终止,所以,在线程的start_routine函数中,不能采用exit。

线程的终止有三种方式:

1)线程的start_routine函数代码结束,自然消亡。

2)线程的start_routine函数调用pthread_exit结束。

3)被主进程或其它线程中止。

pthread_exit函数的声明如下:

void pthread_exit(void *retval);

参数retval填空,即0。

需要注意几个问题:

1)线程主函数的函数体中,不能使用return;语句,如果想退出线程,可以用pthread_exit(0);返回。

2)线程可以共享全局变量,当然也可以共享TcpServer的m_clientfd成员变量,但是,创建线程的时候,为什么要把客户端的socket用参数传给线程主函数,而不是直接获取TcpServer.m_clientfd的值,因为主进程调用pthread_create创建线程后,立即返回循环重新Accept,创建线程需要时间,如果在这段时间内有新的客户端连接上来,TcpServer.m_clientfd的值会发生改变。

3)TcpServer.m_clientfd的强制转换,在创建线程的时候,代码如下:

    if (pthread_create(&pthid,NULL,pth_main,(void*)((long)TcpServer.m_clientfd))!=0)

线程中的代码如下:

  int clientfd=(long) arg; // arg参数为新客户端的socket。

这种数据类型的转换方法可能会让初学者不理解,在学习指针的时候说过,指针是用来存放变量的地址,不能把整数赋给指针,那现在这是怎么回事?这么说吧,C语言很灵活,数据类型可以强制转换,怎么转过去就怎么转回来。举个例子:水桶是用来装水的,特殊情况下用水桶来装板砖其实也可以,但是,板砖放入水桶的方法和从水桶中取出板砖的方法与水不同,怎么放进去就怎么取出来。

4)book261.cpp程序有一个漏洞,没有保存客户端的socket,主程序退出时,没有关闭客户端的socket,资源没有释放,这么说您可能难以理解,没有关系,等您真的需要编写多线程的socket服务端程序的时候就明白了。

三、线程资源的回收

线程有joinable和unjoinable两种状态,如果线程是joinable状态,当线程主函数终止时(自己退出或调用pthread_exit退出)不会释放线程所占用内存资源和其它资源,这种线程被称为“僵尸线程”。创建线程时默认是非分离的,或者称为可连接的(joinable)。

避免僵尸线程就是如何正确的回收线程资源,有四种方法:

1)方法一:创建线程后,在创建线程的程序中调用pthread_join等待线程退出,一般不会采用这种方法,因为pthread_join会发生阻塞。

  pthread_join(pthid,NULL);

2)方法二:创建线程前,调用pthread_attr_setdetachstate将线程设为detached,这样线程退出时,系统自动回收线程资源。

  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);  // 设置线程的属性。
  pthread_create(&pthid,&attr,pth_main,(void*)((long)TcpServer.m_clientfd);

注意:写demo的时候防止main函数提前退出

3)方法三:创建线程后,在创建线程的程序中调用pthread_detach将新创建的线程设置为detached状态。

  pthread_detach(pthid);

  4)方法四:在线程主函数中调用pthread_detach改变自己的状态。

  pthread_detach(pthread_self());

四、查看线程

1)在top命令中,如果加上-H参数,top中的每一行显示的不是进程,而是一个线程。

top -H

2)在ps命令中加-xH参数也可以显示线程,加grep可以过滤内容。

ps -xH
ps -xH|grep book261

五、应用经验

Linux没有真正意义上的线程,它的实现是由进程来模拟,属于用户级线程。所以,在Linux系统下,进程与线程在性能和资源消耗方面没有本质的差别。

对我们程序员来说,进程不能共享全局数据,线程可以共享全局数据,各位可以根据应用场景选择采用多进程或多线程。

六、线程取消 

七、线程清理 

8、线程信号

 

Logo

更多推荐