您的位置:首页 > 运维架构 > Linux

linux下线程控制

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

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宏,就可以设置在出现死锁状态时要执行的清理函数,从而解决死锁。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息