linux初学- 多线程通信(一)

为何出现线程:

1.进程:一个正在执行的程序,它是资源分配的最小单位。
2.线程:有时称为轻量级进程,程序执行的最小单位,系统毒里调度和分配CPU的基本单位,是进程中的一个实体。一个进程中可以有多个进程,这些线程共享进程的所有资源,线程本身只包含一点必不可少的资源。
进程出现了很多弊端,一是由于进程是资源拥有者,创建,撤销和切换存在较大的时空开销,因此需要引入轻型进程;二是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大

linux初学- 多线程通信(一)_第1张图片
linux初学- 多线程通信(一)_第2张图片

一些线程术语

  • 并发:在同一时刻,只能由一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上由多个进程同时执行的效果。(看起来同时)
  • 并行:指在同一时刻,有多条指令在多个处理器上同时发生(真正的同时)。
  • 同步:彼此有依赖关系的调用不应该“同时发生”,而同步就是要阻止那些“同时发生”的事情。
  • 异步:任何两个彼此独立的操作是异步的,它表明事情独立发生。

多线程的优势:

在多处理器中开发程序的并行性

  • 在等待慢速IO操作时,程序可以执行其他操作,提高并发性
  • 模块化的变成,能更清晰表达程序中独立事件的关系。
  • 占用较少的系统资源

创建线程

linux初学- 多线程通信(一)_第3张图片
int pthread_create(pthread_t *restrict tidp , const pthread_attr *restrict attr, void *(*start_routine(void *), void restrict arg)

-参数

  • 新线程的id,如果成功则新县城的id会填充到tidp指向的内存
  • 线程属性(调度策略,继承性,分离性)
  • 回调函数(新线程要执行的函数)
  • 回调函数的参数

-返回值

  • 成功为0
  • 失败返回错误码

-编译时需要连接库 lpthread

#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "string.h"
void print_id(char *s)
{
	pid_t pid;
	pthread_t tid;
	
	pid =getpid();
	pid = pthread_self();//获取线程自身ID
	printf("%s pid is %u,tid is 0x%x\n",s,pid,tid);
}
void *thread_fun(void *arg)
{
	print_id(arg);
	retuen(void *)0;
}
int main()
{
	pthread_t ntid;
	int err;
	err =pthread_create(&nyid,NULL,thread_fun,"new thread");
	if(err!=0)
	{
		printf("create new thread failed\n");
		return 0;
	}
	print_id("man thread :");
	skeep(2);
	return 0;
}


多线程,有想同的pid 不同的tid

线程的生命周期

主线程的特殊性

linux初学- 多线程通信(一)_第4张图片
linux初学- 多线程通信(一)_第5张图片
注意类型的转换 在对stu.name赋值 ,用 memcpy(stu.name, “xxx”,size)
sleep(1);在main中是为了防止主线程结束会终止其他的子进程。或者主线程中调用pthread_exit(rval);这样进程就会等待所有进程结束时才结束。

线程的基本状态

linux初学- 多线程通信(一)_第6张图片

  • 当线程刚被创建时就处于就绪态,或者解除阻塞后也会处于就绪态。就绪的线程在等待一个可用的处理器,当一个运行的线程被抢占,它立刻回到就绪态。
  • 处理器选中一个就绪态的线程执行
  • 试图加锁一个已经被锁住的互斥量;等待某个条件变量;调用singwait等待尚未的信号;执行无法完成的I/O信号;由于内存的错误。
  • 线程通常启动函数中返回来终止自己,或者调用pthread_exit退出,或取消线程
    ![在这里插入图片描述]linux初学- 多线程通信(一)_第7张图片

回收:
分离一个线程并不影响它,仅仅是通知当前系统该系统结束时,其所属的资源可以回收。一个没有被分离线程在终止时会保留它的虚拟内存,包括其堆栈和其他系统资源,有时这种称为僵尸线程。
如果线程具有分离属性,线程终止时会被立刻回收,释放掉所有线程终止时未释放的系统资源和进程资源等。

int pthread_ioin(pthread_t tid,void rval)
即是子线程合入主线程,主线程阻塞等待子线程结束,然后回收子线程资源。

int pthread_detach(pthread_t thread)
即主线程与子线程分离,子线程结束后,资源自动回收

int pthread_cancel(pthread_t tid)
取消线程,成功返回0.但只是发送一个请求,不意味着等待线程终止,而且发送成功也不意味着tid一定会终止。

int pthread_setcancelstate(int state,int oldstate)
设置本线程对Cancel信号的反应,state有两种指:PTHREAD_CANCEL_ENABLE 和 PTHREAD_CANCEL_DISABLE。分别表示收刀信号后设为CANCELED状态和忽略CANCEL信号继续运行。old_state如果不为NULL则存入原来的Cancel状态以便恢复。

int pthread_setcanceltype(int type, int oldtype)
设置本线程取消动作的执行实际,type有两种取值 PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS, 仅当cancel状态未ENABLE时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果补位NULL则存入原来的取消动作类型值。

实例:正确取消一个进程

#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "string.h"
#include <unistd.h>

void *thread_fun(void *arg)
{   
 	int stateval;
 	stateval = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//设置为不可取消
 	if(stateval !=0)
 	{
 		printf("set cancel state failed\n");
 		
 	}
	printf("IM new thread\n");
 	sleep(4);//休眠后,切换到主线程
	printf("about to cancel\n");
	stateval =pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//设置为可取消
	if(stateval !=0)
	{
		printf("set cancel state failed\n");
	}
	printf("first cancel piont\n");//打印完再回到主线程
	printf("second cancel piont\n");
	return(void*)20;
	
}
int main()
{
	pthread_t tid;
	int err,cval,jval;
	void *rval;
	err=pthread_create(&tid,NULL,thread_fun,NULL);
	if(err!=0)
	{
		printf("create thread failed\n");
		return 0;
	}
    sleep(2);
    cval =pthread_cancel(tid);//发送取消信号,只发请求,不等待
    printf("cancel signal has set\n");
    if(cval !=0)
    {
    	printf("cancel thread failed\n");
    	
    }
    jval =pthread_join(tid,&rval);//线程被取消rval被置为PTHCREAD_CANCEL
    printf("new thread exit code is %d\n",(int *)rval);
    return 0;
}

linux初学- 多线程通信(一)_第8张图片
先出现IM new thread 隔四秒后出现后三句,
可见pthread_jion退出码为-1 ,线程已被取消。若为20则证明没有被取消,正常结束。
只能printf出first cancel piont,因为printf()是一个取消点。若用pthread_setcanceltype(PTHREAD_CANCEL_ASYCHRONOUS, NULL)则立即取消不能printf出cancel piont。

你可能感兴趣的:(linux初学- 多线程通信(一))