文档章节

linux 多线程

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

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
西安
Linux多线程并发服务器编程(线程池,FTP服务器)

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

人气王子333
06/26
0
0
socket在windows下和linux下的区别的网络文摘

Windows到Linux代码移植遇到的问题 1、一些常用函数的移植http://www.vckbase.com/document/viewdoc/?id=1586 2、socket------转载&修改(待整理) socket相关程序从windows移植到linux下需要...

雅各宾
2013/07/17
0
0
mwget 多线程版本wget下载工具

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

小运
2013/08/26
0
0
嵌入式Linux学习基础规划篇

嵌入式的学习是需要日积月累的,是通过一点一滴的积累才能成为大神。下面来介绍一下嵌入式linux学习基础规划,目标是达到适应嵌入式应用软件开发、嵌入式系统开发或嵌入式驱动开发的基本素质...

创客学院
04/10
0
0
给PHP扩展/C语言/网络编程初学者推荐的几本书

Linux/Unix系统 深入理解计算机系统 UNIX环境高级编程 深入理解Linux内核 网络通信编程 UNIX网络编程 TCP/IP详解 Linux多线程服务端编程 数据结构与算法 算法导论 《数据结构》(C语言版) ...

Surjur
2014/08/06
0
0
我的Linux系统入坑之路!!!!

  说起Linux,大家可能都知道好,优点比比皆是: 安全、开放、性能突出等。Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操...

linux-tao
2017/10/20
0
0
Python标准库08 多线程与同步 (threading包)

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢! Python主要通过标准库中的threading包来实现多线程。在当今网络时代,每个服务器都会接收到大量的请求...

osDaniel
2014/09/21
0
0
利用Selenium和PhantomJS在Centos下跑测试

做过selenium自动化项目的同学应该都遇到过这样的问题:测试用例太多,运行速度过慢导致团队成员怨声载道。 于是便有了selenium grid和多线程运行selenium测试用例的方法。这些方法各有利弊这...

江边望海
2015/08/06
0
1
Linux下载工具MyGet详解

Linux下载工具MyGet目标设计成一个可扩展的,拥有丰富界面的多线程下载工具,它支持HTTP、FTP、HTTPS、MMS、RTSP等协议。在 http://myget.sourceforge.net/release/myget-0.1.0.tar.bz2下载其...

hcwccc
2014/04/16
0
0
为什么使用BeagleBone BeagleBone的优点

为什么使用BeagleBone BeagleBone的优点 当前,一个典型的基于微控制器板的售价在120元左右,而BeagleBone Black的售价在330元左右。除了更强大的处理器之外,你额外的钱还买到了什么? 1.2....

大学霸
2015/01/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

大数据教程(2.11):keeperalived+nginx高可用集群搭建教程

上一章节博主为大家介绍了目前大型互联网项目的系统架构体系,相信大家应该注意到其中很重要的一块知识nginx技术,在本节博主将为大家分享nginx的相关技术以及配置过程。 一、nginx相关概念 ...

em_aaron
12分钟前
0
0
Apache Directory Studio连接Weblogic内置LDAP

OBIEE默认使用Weblogic内置LDAP管理用户及组。 要整理已存在的用户及组,此前办法是导出安全数据,文本编辑器打开认证文件,使用正则表达式获取用户及组的信息。 后来想到直接用Apache Dire...

wffger
19分钟前
2
0
HFS

FS,它是一种上传文件的软件。 专为个人用户所设计的 HTTP 档案系统 - Http File Server,如果您觉得架设 FTP Server 太麻烦,那么这个软件可以提供您更方便的档案传输系统,下载后无须安装,...

garkey
24分钟前
0
0
Java IO类库之BufferedInputStream

一、BufferedInputStream介绍 /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to * sup......

老韭菜
26分钟前
0
0
STM 32 窗口看门狗

http://bbs.elecfans.com/jishu_805708_1_1.html https://blog.csdn.net/a1985831055/article/details/77404131...

whoisliang
昨天
0
0
Dubbo解析(六)-服务调用

当dubbo消费方和提供方都发布和引用完成后,第四步就是消费方调用提供方。 还是以dubbo的DemoService举例 -- 提供方<dubbo:application name="demo-provider"/><dubbo:registry address="z...

青离
昨天
1
0
iptables规则备份和恢复、firewalld的9个zone以及操作和service的操作

保存以及备份iptalbes规则 设定了的防火墙规则要进行保存,否则系统重启后这些规则就没有了,使用命令 ”service iptables save ” 会把设定好的防火墙规则保存到文件/etc/sysconfig/iptabl...

黄昏残影
昨天
0
0
k8s image

k8s.gcr.io/kube-apiserver-amd64:v1.11.0k8s.gcr.io/kube-controller-manager-amd64:v1.11.0k8s.gcr.io/kube-scheduler-amd64:v1.11.0k8s.gcr.io/kube-proxy-amd64:v1.11.0k8s.gcr.......

分秒
昨天
0
0
数据结构--排序

这篇博客包含了数据结构中多种的排序算法: (1)简单选择:第一趟在A[0]~A[n-1]之间找到最小的,与A[0]进行交换,之后在A[1]~A[n-1]之间进行。。。第i趟在A[i-1]~A[n-1]之间找到最小的,最后...

wangxuwei
昨天
1
0
一名3年工作经验的java程序员应该具备的职业技能

一名3年工作经验的Java程序员应该具备的技能,这可能是Java程序员们比较关心的内容。我这里要说明一下,以下列举的内容不是都要会的东西—-但是如果你掌握得越多,最终能得到的评价、拿到的薪...

老道士
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部