线程解析(四)
来源:互联网 发布:win7一直在识别网络 编辑:程序博客网 时间:2024/06/05 06:40
作者:曹忠明,华清远见嵌入式学院讲师。
一、线程控制
上一节我们讲了使用互斥量实现线程的同步,这里我们介绍一下另外一种常用的方法,POSIX提供的无名信号量sem,PV原语是对整数计数器信号量sem的操作,P操作判断sem资源数是否为0,不为0则进行P操作,一次P操作可使sem减一,而一次V操作可使sem加一。下面是POSIX提供的一些接口函数:
1、信号量初始化
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
函数参数:
sem:信号量
pshared:一个参数一般为0,表示同一个进程中的线程共享一个信号量。
value:信号量资源个数
2、其余函数
int sem_wait (sem_t* sem);
int sem_trywait (sem_t* sem);
int sem_post (sem_t* sem);
int sem_getvalue (sem_t* sem);
int sem_destroy (sem_t* sem);
sem_wait和sem_trywait相当于P操作,它们都能将信号量的值减一,两者的区别在于若信号量的值小于零时,sem_wait将会阻塞进程,而sem_trywait则会立即返回。
sem_post相当于V操作,它将信号量的值加一,同时发出唤醒的信号给等待的进程(或线程)。
sem_getvalue 得到信号量的值。
sem_destroy 摧毁信号量。
下面用一个例程说明信号量的使用:
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <semaphore.h>
sem_t sem;
pid_t gettid(void)
{
return syscall(SYS_gettid);
}
void *thread_a(void *arg)
{
printf("thread a enter/n");
sem_wait(&sem); //sem - 1
printf("thread a P operation/n");
sleep(10);
sem_post(&sem); //sem + 1
printf("thread a V operation/n");
}
void *thread_b(void *arg)
{
printf("thread b enter/n");
sem_wait(&sem); //sem - 1
printf("thread b P operation/n");
sleep(10);
sem_post(&sem); //sem + 1
printf("thread b V operation/n");
}
int main(int argc, char **argv)
{
pthread_t tid_a,tid_b;
int err;
sem_init(&sem, 0, 1);
err = pthread_create(&tid_a,NULL,thread_a,NULL);
if(err < 0)
{
perror("pthread_create thread_a");
}
err = pthread_create(&tid_b,NULL,thread_b,NULL);
if(err < 0)
{
perror("pthread_create thread_a");
}
sleep(30);
sem_destroy(&sem);
printf("the main close/n");
return 0;
}
二、POSIX tid和linux tid
前面我们说创建线程的时候提到一个函数pthread_self,这个函数使POSIX线程库中的一个函数,通过这个函数可以获得线程的ID,可是我们打印出来这个ID会发现这个ID是一个很大的数字。没有得到我们想象的一个数字,其实这个ID是POSIX线程库提供的一个数字,而linux内核中也为这个线程提供了一个ID,这个ID可以通过gettid获得,gettid是linux内核提供的一个系统调用,Glibc没有封装函数,只能通过系统调用实现。
POSIX:
#include <pthread>
pthread_t pthread_self(void);
linux系统调用:
#include <sys/types.h>
#include <sys/syscall.h>
pid_t gettid(void)
{
return syscall(SYS_gettid);
}
下面我们通过一个例程看下这两个函数的区别。
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
pid_t gettid(void)
{
return syscall(SYS_gettid);
}
void *thread_a(void *arg)
{
printf("thread a enter/n");
pthread_t posix_tid;
pid_t linux_tid;
pid_t pid;
posix_tid = pthread_self();
linux_tid = gettid();
pid = getpid();
printf("pid = %x, posix_tid = %x, linux_tid = %x/n", pid, posix_tid, linux_tid);
}
void *thread_b(void *arg)
{
printf("thread b enter/n");
pthread_t posix_tid;
pid_t linux_tid;
pid_t pid;
posix_tid = pthread_self();
linux_tid = gettid();
pid = getpid();
printf("pid = %x, posix_tid = %x, linux_tid = %x/n", pid, posix_tid, linux_tid);
}
int main(int argc, char **argv)
{
pthread_t tid_a,tid_b;
int err;
err = pthread_create(&tid_a,NULL,thread_a,NULL);
if(err < 0)
{
perror("pthread_create thread_a");
}
err = pthread_create(&tid_b,NULL,thread_b,NULL);
if(err < 0)
{
perror("pthread_create thread_a");
}
sleep(5);
printf("the main close/n");
return 0;
}
程序运行结果:
thread a enter
pid = 3b89, posix_tid = b7fd4b90, linux_tid = 3b8a
thread b enter
pid = 3b89, posix_tid = b75d3b90, linux_tid = 3b8b
the main close
通过这个函数我们可以发现posix提供的这个ID不是很有规律,而linux内核为线程提供的ID是经跟在主进程进程号的数字,如上面程序中主进程ID为3b89而两个线程的ID分别为3b8a,3b8b。
- 线程解析(四)
- 线程解析(四)
- 线程解析(四)
- Android线程池(四)ThreadPoolExecutor类源码解析
- java线程池解析和四种线程池的使用
- 线程解析
- 线程解析
- java线程深度解析(四)——并发模型(Master-Worker)
- java线程深度解析(四)——并发模型(Master-Worker)
- java事务全解析(四)--成功的案例(自己实现一个线程安全的TransactionManager)
- 线程【四】线程内定时器
- 驯服Java线程(四)
- 四种线程同步
- 四. 线程间通讯
- COM线程模型(四)
- java线程停止【四】
- 线程系列四
- Jetty学习【四】 线程
- Web 开发与设计之 Google 兵器谱
- CAS单点登录
- 线程解析(三)
- cgi-bin是什么
- C程序:使用 googletest 测试框架
- 线程解析(四)
- android构建自定义的视图组件
- 砂眼的并发症
- oracle客户端 连接PL/SQL
- mysql 子查询删除记录
- Displaytag的使用三
- 多进程与多线程的选择
- C程序:cont char *p 和 char* const p 区别及记忆方法
- Oracle中的Hash Join祥解