linux 多线程
linux 多线程
突然帅了 发表于4年前
linux 多线程
  • 发表于 4年前
  • 阅读 46
  • 收藏 1
  • 点赞 0
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

1、创建新线程

//#include<pthread.h>
//int pthread_equal(pthread_t tid1,pthread_t tid2); 比较线程ID是否相同
//pthread_t pthread_self(void); 获取当前线程ID
//int pthread_create(pthread_t &ntid, const pthread_attr_t *restrict attr.void *(*thr_fn) (void),void *restrict arg);创建新线程,并把新线程ID传给ntid


#include<pthread.h>
#include"apue.h"

pthread_t ntid; 

void printids(const char *s) 

pid_t pid; 
pthread_t tid; 
pid=getpid();//获取自身进程ID 
tid=pthread_self();//获取自身线程ID 
printf("%s pid %u tid %u (0x%x)\n ",s,(unsigned int)pid,(unsigned int)tid,(unsigned int)tid); 


void *thr_fn(void *arg)//新线程开始执行处的函数 

printids("newthread: ");//输出新线程信息 
return((void*)0); 


int main(void)
{
int err;
err=pthread_create(&ntid,NULL,thr_fn,NULL);//创建新线程,并将新线程ID传给ntid
if(err!=0) printf("can't creat thread:%s\n",strerror(err)); 
printids("main thread: ");//输出主线程信息 
sleep(1); 
exit(0); 
}

2、子线程的退出、取消、从例程中返回

//#include<pthread.h>
//1  void pthread_exit(void *rval_ptr); 线程调用pthread_exit函数退出
//2  int pthread_cancel(pthread_t tid); 取消指定线程
//3  从例程中返回
//int pthread_join(pthread_t tid,void **ptr);线程自身变成分离状态,直到指定ID为tid的线程调用pthread_exit结束 或者 指定线程从启动例程返回 或者 指定线程被取消,就获取3种情况的rual_ptr的值,并传给ptr
 
#include<pthread.h>
#include"apue.h"
#include<stdio.h>

void * thr_fn1(void *arg)
{
 printf("thread  1  returning\n");
 return ((void*)1); //线程从例程中返回,其地址为1
}


void * thr_fn2(void *arg)
{
 printf("thread  2  exit\n");
 pthread_exit((void*)2); //线程退出,其地址为2
}

int main()
{
 int err;
 pthread_t ntid1,ntid2; //用于获取创建新线程的ID号
 void *tret;
 err=pthread_create(&ntid1,NULL,thr_fn1,NULL); //创建新线程1
 if(err!=0) printf("创建新线程1不成功: %s\n",strerror(err));
 err=pthread_create(&ntid2,NULL,thr_fn2,NULL); //创建新线程2
 if(err!=0) printf("创建新线程2不成功:%s\n",strerror(err));
 err=pthread_join(ntid1,&tret); //使其处于分离状态,直到指定线程执行结束
 if(err!=0) printf("获取线程1结束状态值不成功:%s\n",strerror(err));
 printf("线程1的结束状态值: %d\n",(int)tret); //打印新线程1的结束状态值
 err=pthread_join(ntid2,&tret);
 if(err!=0) printf("获取线程2结束状态值不成功:%s\n",strerror(err));
 printf("线程2的结束状态值:%d\n",(int)tret);
 exit(0);
}

3、获取线程的结束状态

#include<pthread.h>
#include"apue.h"

struct foo
{
int a,b,c,d;
};

void printfoo(const char *s,const struct foo *fp)
{
 printf(s);
 printf("struct foo  at 0x%x\n ",(unsigned)fp);
 printf("f.a=%d\n",fp->a);
 printf("f.b=%d\n",fp->b);
 printf("f.c=%d\n",fp->c);
 printf("f.d=%d\n",fp->d);
}

void * thr_fn1(void * arg)
{
 struct foo f={1,2,3,4};
 printfoo("thread 1:\n",&f);
 pthread_exit((void *)&f);
}
 
void * thr_fn2(void *arg)
{
 pthread_t myself;
 myself=pthread_self();
 printf("thread 2 ID=%d\n",(unsigned int)myself);
 pthread_exit((void *)0);
}

int main()
{
 pthread_t ntid1,ntid2;
 int i;
 struct foo *p;
 pthread_create(&ntid1,NULL,thr_fn1,NULL);
 pthread_join(ntid1,(void *)&p);
 printf("thr_fn1 return :0x%x\n",p);
 pthread_create(&ntid2,NULL,thr_fn2,NULL);
 pthread_join(ntid2,&i);
 printf("thr_fn2 return :%d\n",i);
 sleep(1);
 printfoo("main pthread :\n",p);
 exit(0);
}

4、线程结束时执行的线程清理处理程序

// #include<pthread.h>
//void pthread_cleanup_push(void (*rtn)(void *), void *arg);  线程退出时安排它的线程清理处理函数 ,由于存放在线程栈中,故逆序执行的
//void pthread_cleanup_pop(int execute);  执行安排好的线程清理处理函数,但execute=0时,清理处理函数不会被调用


#include<pthread.h>
#include"apue.h"

void cleanup(void *arg) //线程清理处理函数
{
printf("cleanup: %s\n",(char *)arg);  
}

void *thr_fn1(void *arg)
{
printf("pthread  1  start\n");
pthread_cleanup_push(cleanup,"pthread 1 first hander"); //安排线程清理处理函数
pthread_cleanup_push(cleanup,"pthread 1 second hander");
printf("thread 1 complete\n");
pthread_cleanup_pop(0); // 执行线程清理处理函数,execute=0时,清理处理函数不会被调用执行
pthread_cleanup_pop(0); //
return ((void *)1); // 当线程从例程中返回时,其线程清理处理函数不会调用
}

void *thr_fn2(void *arg)
{
printf("pthread  2  start\n");
pthread_cleanup_push(cleanup,"pthread 2 first hander");
pthread_cleanup_push(cleanup,"pthread 2 second hander");
printf("thread 2 complete\n");
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
pthread_exit((void *)2); 
}

int main(void)
{
pthread_t ntid1,ntid2;
void *tret;
pthread_create(&ntid1,NULL,thr_fn1,NULL); //创建新线程
pthread_create(&ntid2,NULL,thr_fn2,NULL);
pthread_join(ntid1,&tret);  //使主线程进入分离状态,直到线程ID=ntid1退出,并把rval_ptr(地址)返回给tret
printf("thr_fn1 finish zhuangtai : %d\n",(int)tret); // 打印线程ID=ntid1退出时的rval_ptr
pthread_join(ntid2,&tret);
printf("thr_fn2 finish zhuangtai : %d\n",(int)tret); // 打印线程ID=ntid1退出时的rval_ptr
exit(0);
}

5、多线程的互斥量mutex

//#include<pthread.h>
// int  pthread_mutex_init(pthread_mutex_t  *mutex,const  pthread_mutex_t  *restrict arrt);互斥量使用前必须初始化,一种是把mutex置为PTHREAD_MUTEX_INITALIZER(如果是静态分配的互斥量),一种是调用本函数进行初始化;attr为NULL时,表使用默认的属性进行初始化。
// int  pthread_mutex_destroy(pthread_mutex_t  *mutex); 如果是动态分配的互斥量需要调用本函数释放内存空间
// int  pthread_mutex_lock(pthread_mutex_t  *mutex);对互斥量加锁,若已经有别的线程进行了加锁,则本线程将自我阻塞,直到互斥量被解锁
// int  pthread_mutex_unlock(pthread_mutex_t *mutex);对互斥量解锁
// int  pthread_mutex_trylock(pthread_mutex_t *mutex);尝试加锁,但不阻塞

#include<pthread.h>
#include"apue.h"
struct foo
{
int f_count;//对象的链接数
...................
pthread_mutex_t f_lock;//保护对f_count异步进行访问
}

struct foo *alloc(void) //申请一个新对象
{
struct foo *fp;
if((fp=malloc(sizeof(struct foo)))!=NULL)//为新对象分配空间
  {
fp->f_count=1;//该对象的链接数初始化为1 ,此处无需互斥量控制,因为在未把该对象放到一个列表之前,当前分配线程是唯一可以访问该对象的线程
if(pthread_mutex_init(fp->f_lock,NULL)!=0)//初始化该对象的互斥量
    {
free(fp);
return (NULL);
    }
  }
return (fp);//返回指向新对象的指针,以方便把该对象放入一个列表中
}

void hold(struct foo *fp)//访问指定的对象
  {
pthread_mutex_lock(&fp->f_lock);
fp->f_count++;
pthread_mutex_unlock(&fp->f_lock);
  }


void rele(struct foo *fp)
  {
pthread_mutex_lock(&fp->f_lock);
if(--fp->f_count==0)//若该节点的链接数为0时,就删除该对象
    {
pthread_mutex_unlock(&fp->f_lock);
pthread_mutex_destroy(&fp->f_lock);
free(fp);
    }
else 
pthread_mutex_unlock(&fp->f_lock);
  }

7、构造散列表,并控制多线程对该表的互斥访问

#include<pthread.h>
#include"apue.h"
#define NASHMAX 30 //散列表的大小
#define HASH(fp)  ((unsigned long)fp)%HASHMAX //定义散列函数

struct foo *fh(HASHMAX); //pthread_mutex_t    hashlock=PTHREAD_MUTEX_INITLAIZER; //初始化静态分配的互斥量,保护散列表的互斥访问和f_count

struct foo //定义对象
{
int f_count; //该对象的链接数
int f_id;
struct foo *next;
pthread_mutex_t f_lock;//保护f_id
}

struct foo *alloc(void)//申请一个对象,并放入散列表的相应队列
{
struct foo *fp;
int idx;
if((fp=malloc(sizeof(struct foo)))!=NULL)
  {
fp->f_count=1;//链接数初始化为1
pthread_mutex_init(&f->lock);
idx=HASH(fp);//计算散列值
pthread_mutex_lock(&hashlock);//锁定散列表
fp->next=fh[idx];//把新申请的对象放入散列表的链表里
fh[idx]=fp;//原文书中出错
pthread_mutex_lock(&fp->f_lock);
prhead_mutex_unlock(&hashlock);
.........
pthread_mutex_unlock(&fp->f_lock);
  }
return (fp);//
}

void  hold(struct foo *fp)//访问一对象,将该对象的链接数加1
{
pthread_mutex_lock(&hashlock);//对f_count加锁
fp->f_count++;
pthread_mutex_unlock(&hashlock);
}

struct foo *find(int id)//查找链表中对象的f_id=id的对象,并返回对象的指针
{
struct foo *fp;
int idx;
idx=HASH(fp);
pthread_mutex_lock(&hashlock);
for(fp=fh[idx];fp!=NULL;fp=fp->next)//从链表头查找
  {
if(fp->f_id==id)
    {
fp->f_count++;
break;
    }
  }
pthread_mutex_unlock(&hashlock);
return (fp);
}

void rele(struct foo *fp)//释放该对象,并将该对象链接数减1
{
struct foo *tfp;
int idx;
pthread_mutex_lock(&hashlock);
if(--fp->f_count==0)//若该对象的链接数为0时,就把该对象从链表中删除
  {
idx=HASH(fp);
tfp=th[idx];
if(tfp==fp)  fh[idx]=fp->next;
else 
    {
while(tfp->next!=fp)
tfp=tfp->next;
tfp->next=fp->next;
    }
pthread_mutex_unlock(&hashlock);
pthread_mutex_destroy(&fp->f_lock);
free(fp);
  }
else
  {
pthread_mutex_unlock(&hashlock);
  }
}

8、多线程的读写锁问题:  以下是多个线程在一个队列中,进行线程的分配和调度问题

// #include<pthread.h>
// int pthread_rwlock_init(pthread_rwlock_t  *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
//  int pthread_rwlock_destroy(pthread_rwlock_t  *rwlock);
// int  int pthread_rwlock_rdlock(pthread_rwlock_t  *restrict rwlock);
//  int pthread_rwlock_wrlock(pthread_rwlock_t  *restrict rwlock);
//  int pthread_rwlock_unlock(pthread_rwlock_t  *restrict rwlock);
//  int pthread_rwlock_tryrdlock(pthread_rwlock_t  *restrict rwlock);
//  int pthread_rwlock_trywrlock(pthread_rwlock_t  *restrict rwlock);

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

struct job 
{
struct job *j_next;
struct job *j_prev;
pthread_t j_id;
};

struct queue
{
struct job *q_head;
struct job *q_tail;
pthread_rwlock_t q_lock;
};

int queue_init(struct queue *qp)
{
int err;
qp->q_head=NULL;
qp->q_tail=NULL;
err=pthread_rwlock_init(&qp->q_lock);
if(err!=0) return (err);
return (0);
}

int job_insert(struct queue *qp,struct job *jp)
{
pthread_rwlock_wrlock(&qp->q_lock);
jp->next=qp->q_head;
jp->j_prev=NULL;
if(qp->q_head!=NULL)  qp->q_head->j_prev=jp;
else 
qp->q_tail=jp;
qp->q_head=jp;
pthread_rwlock_unlock(&qp->q_lock);
}

void job_append(struct queue *qp,struct job *jp)
{
pthread_rwlock_wrlock(&qp->q_lock);
jp->next=NULL;
jp->j_prev=qp->q_tail;
if(qp->q_tail!=NULL)  qp->q_tail->j_next=jp;
else 
qp->q_head=jp;
qp->q_tail=jp;
pthread_rwlock_unlock(&qp->q_lock);
}

void job_remove(struct queue *qp,struct job *jp)
{
pthread_rwlock_wrlock(&qp->q_lock);
if(jp==qp->q_head)
  {
qp->q_head=jp->j_next;
if(qp->q_tail==jp)
qp->q_tail=NULL;
  }
else
if(jp==qp->q_tail)
  {
qp->q_tail=jp->j_prev;
if(qp->q_head==jp)
qp->q_head=NULL;
  }
else
  {
jp->j_prev->j_next=jp->j_next;
jp->j_next->j_prev=jp->j_prev;
  }
pthread_rwlock_unlock(&qp->q_lock);
}

struct job *job_find(struct queue *qp,pthread_t id)
{
struct job *jp;
pthread_rwlock_rdlock(&qp->q_lock);
for(jp=qp->q_head;jp!=NULL;jp=jp->j_next)
if(pthread_equal(jp->j_id,id)) break;
pthread_rwlock_unlock(&qp->q_lock);
return (jp);
}











































































































































































































































































































































































































































































标签: 线程 linux
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 8
博文 86
码字总数 28698
×
突然帅了
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: