• Linux 线程


    一、基础概念

    1.线程:一个程序执行的多个执行路线称为线程。轻量级别的进程,程序执行的最小单元;
    2.特点:多个线程共享一个进程的地址空间;

    二、线程创建使用相关函数

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

    //返回值:成功返回0 ,失败返回错误码,不一定置errno;
    //参数:
    //thread  获得线程ID
    //attr    线程的属性(分离属性和结合属性),通常为NULL表示使用默认属性(结合属性)
    //start_routine  线程的执行函数,采用回调方式执行线程函数
    //arg   给线程函数传递的参数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    //练习:主线程与子线程多数据交换,以及主线程改变子线程的数据

    #include
    #include
    #include
    struct data1
    {
    	int int_data;
    	short short_data;
    	char char_data;
    };
    
    int global=0;
    
    void *func1(void *arg1)
    {
    	struct data1 getData=*(struct data1 *)arg1;
    	while(1)
    	{
    		sleep(1);
    		printf("int_data:%d  short_data :%d  char_data :%d\n",getData.int_data,getData.short_data,getData.char_data);
    		global++;
    	}
    }
    void *func2(void *arg2)
    {
    	int *gDtata=(int *)arg2;
    	while(1)
    	{
    		sleep(1);
    		printf("global:%d   data:%d\n",global,*gDtata);
    		(*gDtata)++;
    	}
    }
    int main(int argc, const char *argv[])
    {
    	pthread_t tid,tid1;
    	int ret;
    	int data=10;
    	struct data1 past_data={20,40,60};
    	ret=pthread_create(&tid,NULL,func1,&past_data);
    	if(ret!=0)
    	{
    		perror("Fail to pthread_create");
    		return -1;
    	}
    	ret=pthread_create(&tid1,NULL,func2,&data);
    	if(ret!=0)
    	{
    		perror("Fail to pthread_create");
    		return -1;
    	}
    	while(1)
    	{
    		printf("main running:%d\n",data);
    		sleep(1);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    2.线程终止
    void pthread_exit(void *retval);//
    //结束当前线程的执行
    //参数:
    /retval //给等待的线程带一个地址值,如果无则填NULL;
    (1)如果在主线程中调用了return 或者exit()函数,则进程结束,所有线程均结束;
    (2)如果主线程调用了pthread_exit()函数,则仅仅是主线程消亡,主线程等所有子线程结束时才会结束。
    //示例:主线程程中return 前调用pthread_exit()函数,等子线程结束,主进程才结束

    #include
    #include
    void *func(void *arg)
    {
    	int data=*(int *)arg;
    	while(1)
    	{
    		sleep(1);
    		if(data==4)
    		{
    			break;
    		}
    		printf("thread 1  value:%d\n",data++);
    	}
    	pthread_exit(NULL);
    }
    int main(int argc, const char *argv[])
    {
    	int ret;
    	int value=0;
    	pthread_t tid;
    	ret =pthread_create(&tid,NULL,func,&value);
    	if(ret!=0)
    	{
    		perror("Fail to pthread_create");
    		return -1;
    	}
    	pthread_exit(NULL);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3.等待线程退出函数
    (1)int pthread_join(pthread_t thread,void ** pval);//阻塞的方式等待线程结束
    //通过pthread_exit(&value);传回线程内部指针,可以带回返回值给二级指针pval,但是,如果传回的是普通变量的值,则在该线程结束后局部变量被回收,值就没有了,可以把传回值value 设置成static 静态变量。
    //示例:

    #include
    #include
    #include
    #include
    #include
    void *func(void *arg)
    {
    
    	int data=*(int *)arg;
    	static int value=30;
    
    	while(1)
    	{
    		sleep(1);
    		if(data==4)
    		{
    			break;
    		}
    		printf("thread 1  value:%d\n",data++);
    	}
    	printf("thread 1 value:%p\n",&value);
    
    	pthread_exit(&value);
    }
    
    int main(int argc, const char *argv[])
    {
    	int ret;
    	int value=0;
    
    	int *pval=NULL;
    
    	pthread_t tid;
    
    	ret =pthread_create(&tid,NULL,func,&value);
    	if(ret!=0)
    	{
    		perror("Fail to pthread_create");
    		return -1;
    	}
    	
    	ret=pthread_join(tid,(void **)&pval);
    	if(ret!=0)
    	{
    		fprintf(stderr,"Fail to pthread_join %s\n",strerror(errno));
    		return -1;
    	}
    	printf("pval=%p value:%d\n",pval,*pval);
    	pthread_exit(NULL);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    4.创建分离式线程
    int pthread_detach(pthread_t thread);//非阻塞
    //功能:将线程标记为分离式线程
    //参数:
    //thread 线程的tid号
    //返回值:成功返回0,失败返回错误码
    (1)分离式线程的特点:线程结束时,系统会自动回收资源,不需要pthread_join()函数来阻塞回收;
    //示例:

    //创建线程后,在主线程添加
    pthread_detach(tid);//把需要改成分离式线程的线程号填进去,这里看不到效果,子线程结束后,系统自动回收资源。
    
    • 1
    • 2

    5.取消一个线程
    int pthread_cancel(pthread_t thread);//取消一个线程的执行(取消别人)
    //参数:
    //thread 线程的tid号
    //返回值:成功返回0,失败返回错误码
    //示例:创建子线程,主线程休眠4秒取消子线程,并回收子线程资源。

    #include
    #include
    
    void *func(void *arg)
    {
    	
    	while(1)
    	{
    		sleep(1);
    		printf("thread 1 running\n");
    	}
    pthread_exit(NULL);//
    }
    int main(int argc,const char *argv[])
    {
    	pthread_t tid;
    	int ret;
    	ret=pthread_create(&tid,NULL,func,NULL);
    	if(ret!=0)
    	{
    		perror("Fail to pthread_create");
    		return -1;
    	}
    	sleep(4);
    	ret=pthread_cancel(tid);//取消子线程,成功返回0,失败返回错误码
    	if(ret!=0)
    	{
    		perror("Fail to pthread_cance");
    		return -1;
    	}	
    	pthread_exit(NULL);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    //示例:打开一个文件,创建两个子进程,一个子进程写,一个子进程读并且打印,当读到"quit"时,退出子进程。

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    int gTid;//其实可以通过传参把读线程的线程号传入写线程
    void *func1(void *arg1)//read
    {
    	char buf[1024]={0};
    	int fd=*(int *)arg1;
    	while(1)
    	{
    		memset(buf,0,sizeof(buf));
    		ssize_t ret=read(fd,buf,sizeof(buf));
    		if(ret<0)
    		{
    			perror("Fail to read");
    			return NULL;
    		}
    		else if(ret==0)
    		{
    			continue;
    		}
    		else
    		{
    			printf("p:%s\n",buf);
    		}
    	}
    	pthread_exit(NULL);
    }
    void *func2(void *arg2)//write
    {
    	char buf[1024]={0};
    	int fd=*(int *)arg2;
    	while(1)
    	{
    		memset(buf,0,sizeof(buf));
    		fgets(buf,sizeof(buf),stdin);
    
    		buf[strlen(buf)-1]='\0';
    
    		if(strncmp(buf,"quit",4)==0)
    		{
    			pthread_cancel(gTid);
    			break;
    		}
    		write(fd,buf,strlen(buf));
    		lseek(fd,-strlen(buf),SEEK_CUR);		
    	}
    	pthread_exit(NULL);
    }
    int main(int argc, const char *argv[])
    {
    	pthread_t tid1,tid2;
    	int ret;
    	int fd;
    	if(argc!=2)
    	{
    		fprintf(stderr,"usage: %s log.txt",argv[0]);
    		return -1;
    	}
    	fd=open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0666);
    	if(fd<0)
    	{
    		perror("Fail to open");
    		return -1;
    	}
    	ret=pthread_create(&tid1,NULL,func1,&fd);//read
    	if(ret!=0)
    	{
    		perror("Fail to pthread_create");
    		return -1;
    	}
    	gTid=tid1;
    
    	ret=pthread_create(&tid2,NULL,func2,&fd);
    	if(ret!=0)
    	{
    		perror("Fail to pthread_create");
    		return -1;
    	}
    	pthread_exit(NULL);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    6.线程间同步,使用信号量
    //功能:对于两个线程,创建两个(全局变量)信号量A,B(sem_t A,B),先对A,B赋初值,A 为1(sem_init(&A,0,1),B为0(sem_init(&B,0,0),在第一个线程中使用sem_wait(&A),当A为0时阻塞,当使用sem_post(&A)时,释放A,此时sem_wait(&A)可以顺利执行。
    (1)建立全局变量的信号量:sem_t sem_A;
    (2)初始化信号量:

    int sem_init(sem_t *sem,int pshared,unsigned int value);
    //返回值:成功返回0,失败返回-1
    //参数:
    //sem   第一步创建的 信号量;
    //pshared   0:线程间使用
    //value     信号量的初始值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (3)P操作

    int sem_wait(sem_t *sem);
    //功能:申请资源,如果资源为0则阻塞调用者
    //返回值:成功返回0,失败返回-1
    //参数:
    //sem   :信号量的地址
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (3)V操作

    int sem_post(sem_t *sem);
    //功能:释放资源,如果有线程等待则唤醒等待的线程
    //返回值:成功返回0,失败返回-1
    //参数:
    //sem   :信号量的地址
    
    • 1
    • 2
    • 3
    • 4
    • 5

    //示例:

    #include
    #include
    #include
    #include
    #include
    
    sem_t sem_read,sem_write;
    struct data_t
    {
    	char name[20];
    	int id;
    	int score;
    };
    struct data_t stu;
    
    void *func1(void *arg1)//write
    {
    	char buf[1024]={0};
    	while(1)
    	{
    		sem_wait(&sem_write);
    		memset(&stu,0,sizeof(struct data_t));
    		memset(buf,0,sizeof(buf));
    		printf("name:");
    		fgets(buf,sizeof(buf),stdin);
    		fflush(stdin);
    		buf[strlen(buf)-1]='\0';
    		strcpy(stu.name,buf);
    		
    		if((stu.name,"quit",4)==0)
    		{
    			break;
    		}
    		printf("ID:");
    		scanf("%d",&stu.id);
    		getchar();
    		printf("score:");
    		scanf("%d",&stu.score);
    		getchar();//取走换行符
    		sem_post(&sem_read);
    	}
    	pthread_exit(NULL);
    }
    void *func2(void *arg2)
    {
    	while(1)
    	{
    		sem_wait(&sem_read);
    		printf("name:%s   id:%d  score:%d\n",stu.name,stu.id,stu.score);
    		sem_post(&sem_write);//释放信号量
    	}
    }
    
    int main(int argc, const char *argv[])
    {
    	pthread_t tid1,tid2;
    	int ret;
    	sem_init(&sem_read,0,0);//初始化信号量
    	sem_init(&sem_write,0,1);
    	ret=pthread_create(&tid1,NULL,func1,NULL);
    	if(ret!=0)
    	{
    		perror("Fail to create_thread");
    		return -1;
    	}
    	ret=pthread_create(&tid2,NULL,func2,NULL);
    	if(ret!=0)
    	{
    		perror("Fail to create_thread");
    		return -1;
    	}
    	pthread_exit(NULL);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    7.线程间互斥 --互斥锁
    //功能:一个线程访问资源的时候,不允许其他线程访问;
    宏创建互斥锁

    pthread_mutex_t mutex=
    
    • 1

    (1)定义互斥锁

     pthread_mutex_t mlock;//定义了一个叫mlock的互斥锁
    
    • 1

    (2)初始化互斥锁

    int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
    //返回值:成功返回0,失败返回-1
    //参数:
    //mutex  互斥锁地址
    //attr   默认值NULL;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (3)获得互斥锁

    int pthread_mutex_lock(pthread_mutex_t *mutex);
    //功能:获得互斥锁则立即返回,否则阻塞直到获得互斥锁
    //返回值:成功返回0,失败返回-1
    //参数: mutex  互斥锁地址
    
    • 1
    • 2
    • 3
    • 4

    (4)获得互斥锁

    int pthread_mutex_unlock(pthread_mutex_t *mutex);
    //功能:释放互斥锁
    //返回值:成功返回0,失败返回-1
    //参数: mutex  互斥锁地址
    
    • 1
    • 2
    • 3
    • 4

    (5)销毁互斥锁

    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    //功能:销毁互斥锁
    //返回值:成功返回0,失败返回-1
    //参数: mutex  互斥锁地址
    
    • 1
    • 2
    • 3
    • 4

    //示例:

    #include
    #include
    #include
    #include
    #include
    int pro=0;
    pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//定义互斥锁同时初始化
    pthread_cond_t cond=PTHREAD_COND_INITIALIZER;//定义条件变量同时初始化
    
    void *func1(void *arg)
    {
    	int data;
    	while(1)
    	{
    		
    		pthread_mutex_lock(&mutex);//抢占互斥锁
    		while(pro!=0)
    		{
    			pthread_cond_wait(&cond,&mutex);//	
    
    		}
    
    		data=rand()%100;
    		pro=data;
    		printf("producer:%d\n",pro);
    		pthread_mutex_unlock(&mutex);//释放互斥锁
    		pthread_cond_signal(&cond);
    	
    	}
    
    	pthread_exit(NULL);
    
    }
    
    void *func2(void *arg)
    {
    	while(1)
    	{
    		pthread_mutex_lock(&mutex);//抢占互斥锁
    	
    		while(pro==0)
    		{	
    			pthread_cond_wait(&cond,&mutex);//	
    		}
    		printf("pro=%d\n",pro);
    		pro=0;
    		pthread_mutex_unlock(&mutex);//释放互斥锁
    		pthread_cond_signal(&cond);
    
    
    	}
    	pthread_exit(NULL);
    }
    
    
    int main(int argc, const char *argv[])
    {
    	pthread_t tid1,tid2;
    
    	int ret;
    
    	ret=pthread_create(&tid1,NULL,func1,NULL);
    	if(ret!=0)
    	{
    		perror("Fail to pthread_create");
    		return -1;
    	}
    
    	ret=pthread_create(&tid2,NULL,func2,NULL);
    	if(ret!=0)
    	{
    		perror("Fail to pthread_create");
    		return -1;
    	}
    
    
    	pthread_join(tid1,NULL);
    	pthread_join(tid2,NULL);
    	
    	pthread_exit(NULL);
    	pthread_mutex_destroy(&mutex);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    8.条件变量
    (1)定义:条件变量是利用线程间共享的全局变量进行同步通信的一种机制。多个线程等待某一个条件满足,在条件达到时由一个线程去通知其他等待的线程。
    (2)条件变量相关函数。

    pthread_cont_t cond;//定义条件变量
    pthread_cont_init(&cond,NULL);//动态初始化条件变量
    
    //等待条件变量,条件不满足,则阻塞当前进程,
    int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
    
    //唤醒条件变量
    int pthread_cond_broadcast(pthread_cond_t *cond);//唤醒所有等待的线程
    int pthread_cond_signal(pthread_cond_t *cond);//唤醒至少一个等待线程
    
    //销毁条件变量
    pthread_cond_destroy(pthread_cond_t *cond);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    //示例:见互斥锁。

  • 相关阅读:
    Springboot整合阿里云ONS RocketMq(4.0 http)
    人工智能的未来以及人工智能如何影响教育、医学、营销领域
    NoSQL之Redis配置与优化
    LQ0274 密码发生器【水题】
    Linux学习第30天:Linux 自带的 LED 灯驱动实验:驱动开发思维方式的转变势在必行
    【问一问】消息队列
    子不语发生工商变更:注册资本增至3000万元,预计全年净利润下滑
    javaEE -10(11000字详解5层重要协议)
    Golang时间
    Unix时间戳来源含义及与标准时间的互相转换(Python)
  • 原文地址:https://blog.csdn.net/jun8086/article/details/127749763