文档章节

linux 多线程

突然帅了
 突然帅了
发布于 2013/11/03 21:56
字数 2087
阅读 49
收藏 1

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);
}











































































































































































































































































































































































































































































© 著作权归作者所有

共有 人打赏支持
突然帅了
粉丝 8
博文 90
码字总数 28698
作品 0
西安
私信 提问
Android 多线程系统概述及与Linux系统的关系

线程系统的分类 1.1 操作系统内核实现了线程模型(核心型线程) - Windows - 线程与进程的多对多模型 线程效率比较高 Window Thread结构如下图所示: 1.2 操作系统核外实现的线程(用户进程)...

长平狐
2012/09/03
220
0
Linux多线程并发服务器编程(线程池,FTP服务器)

分享网盘下载:https://pan.baidu.com/s/1gfNCcXt 密码: irfk 内容简介 本课程从最基础的进程、线程概念讲起逐步深入,通过理论与实践结合的方式,使学员快说掌握linux多线程网络编程技术,并...

人气王子333
06/26
0
0
求靠谱驻场 1-2 人做 Linux 多线程 C++服务器程序开放

需求:完成 Windows 多线程 C++服务器程序向 Linux 多线程 C++服务器程序的移植 要求: 1. 抽取其中用到的 Win32API, 分为通信类, 多线程类,时间字符串等函数类, 逐一封装成 Linux 的函数...

junshi001
2016/07/19
2
2
mwget 多线程版本wget下载工具

linux运维在操作linux过程中,用得最多的linux下载工具想必一定是wget,没有看到哪一台服务器没装过wget的,或许有人使用 ftp下载,也有人使用多线程的axel以及ProZilla,毫无疑问这两个工具都非...

小运
2013/08/26
0
0
求靠谱驻场 1-2 人做 Linux 多线程 C++服务器程序开放

需求:完成 Windows 多线程 C++服务器程序向 Linux 多线程 C++服务器程序的移植 要求: 1. 抽取其中用到的 Win32API, 分为通信类, 多线程类,时间字符串等函数类, 逐一封装成 Linux 的函数...

junshi001
2016/07/30
1
0

没有更多内容

加载失败,请刷新页面

加载更多

Caffe(二)-Python-自定义网络

这里我们用一个例子先来体验一下 首先定义一下我们的环境变量 $PYTHONPATH,我这儿是Windows开发环境,至于Windows Caffe怎么编译由读者自己下去搞定 我使用的控制台是 Windows PowerShell 添...

Pulsar-V
26分钟前
2
0
ActiveMQ从入门到精通(二)之可靠性机制

ActiveMQ的可靠性机制 缘由( 确认JMS消息) 只要消息被确认之后,才认为消息被成功消费了。消息的成功消费包括三个阶段:客户端接收消息、客户端处理消息以及客户端确认消息。在事务性会话中...

一看就喷亏的小猿
34分钟前
0
0
源码分析 Mybatis 的 foreach 为什么会出现性能问题

背景 最近在做一个类似于综合报表之类的东西,需要查询所有的记录(数据库记录有限制),大概有1W条记录,该报表需要三个表的数据,也就是根据这 1W 个 ID 去执行查询三次数据库,其中,有一...

TSMYK
58分钟前
7
0
IC-CAD Methodology企业实战之openlava

在云计算解决安全问题并成为IC界主流运算平台之前,私有的服务器集群系统仍然是各大IC公司的计算资源平台首选。 现在主流的服务器集群管理系统包括lsf,openlava,SkyForm,三者都属于lsf一系...

李艳青1987
今天
5
0
http response stream 字节流 接收与解码

在接收图片、音频、视频的时候,需要用到二进制流。 浏览器会发给客户端 字节Byte流,一串串的发过来_int8格式 -128~127(十进制),也就是8bit(位)。 客户端接收的时候,对接收到的字节收集,...

大灰狼wow
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部