首页 > 编程语言 > 详细

linux下线程控制

时间:2015-10-25 22:51:27      阅读:394      评论:0      收藏:0      [点我收藏+]

    线程是计算机中独立运行的最小单位,运行时占用很少的系统资源。在多进程情况下,每个进程都有自己独立的地址空间,而在多线程情况下,同意进程内的线程共享进程的地址空间。因此创建新进程就要耗费时间为其分配系统资源,而创建新线程花费的时间要少得多。


1.创建线程

int pthread_create(
    pthread_t *thread,  //线程ID
    const pthread_attr_t *attr, //线程属性,为NULL/0,使用默认属性
    void *(*start_routine) (void *),  //线程代码函数 
    void *arg);      //传递线程代码的数据
例1.创建线程
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>    //这是一个外部库,在编译时需要指定链接库-lpthread

void * thread(void *data)
{
    printf("this is thread111,threadid = %ld\n",pthread_self());
}

int main()
{
    pthread_t thid;
    
    pthread_create(&thid,NULL,thread,NULL);
    //sleep(2);
    pthread_join(thid,(void**)0);
    return 0;
}

结论:

      1.程序结束所有子线程就结束

             解决办法: 等待子线程结束

          a.sleep/pause

          b.pthread_exit(void*retval);  

        c.int pthread_join(

                      pthread_t tid,  //等待子线程tid结束

                      void **retval); //子线程结束的返回值

             如果不加等待子线程结束的语句,main函数执行完会直接退出,不会执行子线程 

       2.创建子线程后,主线程继续完成系统分配的时间片

       3.子线程结束就是线程函数返回

       4.子线程与主线程有同等优先级别

2.线程基本控制

    线程结束可分为内部结束和外部结束:

        内部自动结束:(建议,可以看例二)

    return 返回值;    只能在线程函数中使用

    int pthread_exit(void*);         在任何线程代码中都可以使用,退出当前线程

        外部结束一个线程(处理可以参看下边介绍,防止产生问题):

    pthread_cancel(pthread_t thread);    会产生一些不可预知的问题


 例二:内部结束线程

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

void * thread(void *data)
{
 	while(1){
		printf("this is thread data:%s\n",data);
		//return "thread exit";
		pthread_exit("exit");
	 }
}

int main()
{
	pthread_t thid;
	char *retavl;
	char *data="main";

	pthread_create(&thid,NULL,thread,data);
	pthread_join(thid,(void**)&retavl);
	printf("%s\n",retavl);

	return 0;
}
#gcc pthread_exit.c -o pthread_exit -lpthread
#./pthread_exit
 this is thread data:main
 exit

3.多线程问题及介绍

    对于一个全局变量资源等信息,线程是共享进程的这些资源,存在多个线程对这些数据资源进行操作时,可能会产生一些问题,导致数据成为脏数据。

    为了解决数据脏,可以使用加锁机制;

  3.1.互斥锁/互斥量 mutex(强烈要求成对使用,加锁就需要解锁)

(1).定义互斥量 pthread_mutex_t m;

(2).初始化互斥量 1 pthread_mutex_init(pthread_mutex_t *restrict mutex,

              const pthread_mutexattr_t *restrict attr);

            attr为锁的属性,置NULL/0为默认属性

(3).互斥量操作

置0 pthread_mutex_lock

    判定互斥量若为0:阻塞;为1:先置0,再返回

置1 pthread_mutex_unlock 直接置1返回

(4).释放互斥量pthread_mutex_destroy

例三:使用互斥锁

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

//1,定义互斥量
pthread_mutex_t m;
int a=0,b=0;  //线程共享进程的资源(a,b为全局变量),输出时两个线程同时操作,会导致if(a!=b)出错

void display()
{
	//3.加锁
	pthread_mutex_lock(&m);
	a++;
	b++;
	pthread_mutex_unlock(&m); //解锁
	if(a!=b)
	{
		printf("%d!=%d\n",a,b);
		a=b=0;
	}
}
void *run1()
{
	while(1)
	{
		display();
	}
}

void *run2()
{
	while(1)
	{
		display();
	}
}

main()
{
	pthread_t thid1, thid2;
	//2.初始化锁
	pthread_mutex_init(&m,0);
	pthread_create(&thid1,NULL,(void*)run1,NULL);
	pthread_create(&thid2,NULL,(void*)run2,NULL);
	pthread_join(thid1,(void**)0);
	pthread_join(thid2,(void**)0);
	//4.释放互斥量
	pthread_mutex_destroy(&m);
}

如果不使用互斥锁的话会输出两个明明相等的数不相等:

技术分享

为了防止这种数据脏的问题,就需要使用互斥锁机制。


3.2死锁问题

    在lock与unlock之间,调用pthread_exit或者在线程外部调用pthread_cancel会使其他线程被永久死锁。

    pthread_exit退出线程,为了防止造成死锁,可以在pthread_exit语句前使用解锁语句unlock;

    pthread_cancel退出线程,防止死锁可以使一对宏,这对宏类似于进程atexit函数:

    

 void pthread_cleanup_push(
           void (*routine)(void *),  //回调函数,routine指向处理函数
           void *arg);	//arg为传递给处理函数的参数
 void pthread_cleanup_pop(int execute);
		//execute参数表示执行到pthread_cleanup_pop()时是否在弹出清理函数的同时执行该函数,为0表示不执行,非0为执行;这个参数并不影响异常终止时清理函数的执行。


push进去的函数可能在以下三个时机执行:

1,显示的调用pthread_exit();

2,在cancel点线程被cancel。

3,pthread_cleanup_pop()的参数不为0时。


例四:创建两个线程分别输出奇数和偶数

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

pthread_mutex_t m;
void *handle(void *d)
{
	printf("退出后调用\n");
}

void *runodd(void *d) 
{
	int i=0;
	for(i=1;;i+=2)
	{
		pthread_cleanup_push((void*)handle,0);
		pthread_mutex_lock(&m);
		printf("%d\n",i);
		pthread_mutex_unlock(&m);
		pthread_cleanup_pop(0);  //如果设置为1,它会每次都调用清理函数,设置为0,只在死锁使执行清理函数
	}
}

void *runeven(void *d) 
{
	int i=0;
	for(i=0;;i+=2)
	{
		pthread_mutex_lock(&m);
		printf("%d\n",i);
		pthread_mutex_unlock(&m);
	}
}
main()
{
	pthread_t todd,teven;
	pthread_mutex_init(&m,0);
	pthread_create(&todd,0,runodd,0);
	pthread_create(&teven,0,runeven,0);

	sleep(5);
	pthread_cancel(todd);     

	pthread_join(todd,(void**)0);
	pthread_join(teven,(void**)0);
	pthread_mutex_destroy(&m);
}

在线程代码加锁时,pthread_cancel会使线程在未解锁的情况下退出,从而导致另一个线程获得的所状态为0,一直处于阻塞状态,造成死锁;使用pthread_cleanup_push和pthread_cleanup_pop宏,就可以设置在出现死锁状态时要执行的清理函数,从而解决死锁。

本文出自 “划舞鱼” 博客,请务必保留此出处http://ty1992.blog.51cto.com/7098269/1706004

linux下线程控制

原文:http://ty1992.blog.51cto.com/7098269/1706004

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!