Linux下多线程编程

进程和线程的区别

进程:进程是资源分配的最小单位,是程序执行时的实例,在程序运行时创建。

线程:线程是程序执行的最小单位,调度的基本单位,是进程的一个执行流。

并发和并行的区别

并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。其中两种并发关系分别是同步和互斥。

        同步:指进程间的关系是相互依赖。前一个进程的输出是后一个进程的输入。当前一个进程没有输出时,后一个进程必须等待。

        互斥:进程之间相互排斥地使用临界资源(一次仅允许一个进程使用地共享资源)。

并行:指在同一时刻,有多条指令在多个处理器上同时执行。

同步和异步的区别

同步:指进程间的关系是相互依赖。前一个进程的输出是后一个进程的输入。当前一个进程没有输出时,后一个进程必须等待。就是实时处理(如打电话)

异步:指进程间相互独立。执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。 就是分时处理(如收发短信)。

多线程编程

1.创建新线程

pthread_self函数:  获取线程ID

  • pthread_t pthread_self(void); 返回值:成功:0; 失败:无
  • 线程ID:pthread_t类型,在Linux下为无符号整数(%lu),当前Linux中可理解为:typedef  unsigned long int  pthread_t

pthread_create函数 : 创建一个新线程

  • int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg)
  • 返回值:成功:0; 失败:错误号 
  • 参数1:传出参数,保存系统为我们分配好的线程ID
  • 参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
  • 参数3:函数指针,指向线程主函数(线程体),新创建的线程从start_routine函数的地址开始运行,该函数运行结束,则线程结束。
  • 参数4:线程主函数执行期间所使用的参数,有参数时输入参数的地址,如要传多个参数, 可以用结构封装。
  • //创建线程,返回线程序号和ID
    //Linux编译时加上 -lpthread
    //因为pthread并非Linux系统的默认库,而是POSIX线程库。在Linux中将其作为一个库来使用,因此加上 -lpthread(或-pthread)以显式链接该库。
    //gcc -o more_pthread more_pthread.c -lpthread
    
    #include <stdio.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    void *pth(void * arg);
    
    int main(int argc,char *argv[])
    {
    	int n,i;
    	pthread_t tid;
    
    	if(argc==2)
    	{
    		n=atoi(argv[1]);
    	
    	}
    
    	for(i=0;i<n;i++)
    	{
    		pthread_create(&tid, NULL, pth, (void *)i);
    	}
    
    	sleep(n);
    
    	printf("i am main,main_pthread_id = %lu\n",pthread_self());
    
    	return 0;
    }
    
    void *pth(void *arg)
    {
    	int i;
    
    	i=(int)arg;
    
    	//i=*((int*)arg);
    
    	sleep(i);
    	printf("i am %d thread,thread_id = %lu\n",i+1,pthread_self());
    
    	return NULL;
    
    }
    

    atoi()代表的是ascii to integer,即“把字符串转换成有符号数字”,举例如下:

  • char a="-10";
    char b="9";
    int c=atoi(a)+atoi(b);

    那么计算结果c=-10+9=-1。

  • int main(int argc,char * argv[]),表示的就是argc表示你使用这个程序时,输入的参数的个数,argv[]表示各个参数。

  • 默认argc为1,argv[0]为程序名称。如果输入一个参数,则argc为2,argv[0]为程序名称,argv[1]为输入的那个参数。以此可推出,多个输入参数的情况。

  • 运行结果

  • a920ec051fe34eaa856edb1def8be3f3.png

2. 单个线程退出

pthread_exit函数 : 将单个线程退出

  • void pthread_exit(void *retval); 参数:retval表示线程退出状态,通常传NULL
//退出线程

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

void *pth(void * arg);

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

	if(argc==2)
	{
		n=atoi(argv[1]);
	
	}

	for(i=0;i<n;i++)
	{
		pthread_create(&tid, NULL, pth, (void *)i);
	}

	sleep(n);

	printf("i am main,main_pthread_id = %lu\n",pthread_self());

	return 0;
}

void *pth(void *arg)
{
	int i;

	i=(int)arg;

	if(i==3)
	{
		pthread_exit(NULL);  //退出第四个线程
	}


	sleep(i);
	printf("i am %d thread,thread_id = %lu\n",i+1,pthread_self());

	return NULL;

}

运行结果

4e0c329c8d92414a9aaa7e5faa818a9a.png

 线程中,禁止使用exit函数,会导致进程内所有线程全部退出。

 3.等待线程结束

pthread_join函数:  阻塞等待线程退出,获取线程退出状态 

  • int pthread_join(pthread_t thread, void **retval)
  • thread: 线程标识符,即线程ID,标识唯一线程
  • retval: 用户定义的指针,用来存储被等待线程的返回值
//回收多个子线程

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

int var=10;
void *pth(void * arg);

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


	for(i=0;i<5;i++)
	{
		pthread_create(&tid[i], NULL, pth, (void *)i);
	}

	for(i=0;i<5;i++)
	{
		pthread_join(tid[i],(void**)&ret[i]);
		printf("=======%d  ret=%d\n",i,(int)ret[i]);

	}


	printf("i am main,main_pthread_id = %lu\t var=%d\n",pthread_self(),var);

	sleep(i);

	return 0;
}

void *pth(void *arg)
{
	int i;

	i=(int)arg;

	sleep(i);
	if(i==1)
	{
		var=20;
		printf("var=%d\n",var);
		return (void*)var;
	}

	else if(i==3)
	{
		var=30;
		printf("i am %d pthread,id=%lu,var= %d\n",i+1,pthread_self(),var);

		pthread_exit((void *)var);
	}
	else
	{
		 printf("i am %d pthread,id=%lu,var= %d\n",i+1,pthread_self(),var);
		 pthread_exit((void *)var);
	}



	return NULL;

}

运行结果

9b091374bd35442d838ec60500ce94e9.png

 4.线程分离

pthread_detach函数:  实现线程分离

  • int pthread_detach(pthread_t thread); 成功:0;失败:错误号
  • 指定该状态,线程主动与主控线程断开关系。线程结束后(不会产生僵尸线程),其退出状态不由其他线程获取,而直接自己自动释放(自己清理掉PCB的残留资源)。网络、多线程服务器常用。
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

void *pth(void * arg);

int main(int argc,char *argv[])
{
	int err;
	pthread_t tid;
	void *tret;

#if 1
	pthread_attr_t attr;  //通过线程属性来设置游离态(分离态)
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
	pthread_create(&tid,&attr,pth,NULL);

#else
	pthread_create(&tid,NULL,pth,NULL);
	pthread_detach(tid);    //让线程分离  ----自动退出,无系统残留资源

#endif

	while(1)
	{
		err=pthread_join(tid,&tret);
		printf("thread exit code=%d\n",(int)tret);
		printf("========err=%d\n",err);

		if(err!=0)
		{
			fprintf(stderr,"thread join err:%s\n\n",strerror(err));
		}

		else
		{
			 fprintf(stderr,"thread join err:%s\n\n",(int)tret);
		}

		sleep(2);
	}

	return 0;
}

void *pth(void *arg)
{
	int n=3;

	while(n--)
	{
		printf("thread count %d\n",n);
		sleep(1);
	}

	return (void *)1;
}

运行结果

c672f88795ce4cb396e51b22be57b07c.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值