标签:mod hhhh 操作 err 共享内存 exit 申请 stderr putc
分离: 说明主线程不需要接合子线程 -> 不需要pthread_join子线程 -> 当主线程退出时,子线程还是会退出。
非分离: 说明主线程需要接合子线程 -> 需要pthread_join子线程
默认pthread_create()创建出来的线程都是非分离属性。
思路: 添加分离属性到一个属性变量中,然后使用该属性变量去创建一个新的线程,那么这个线程就是一个分离的线程。
pthread_attr_t attr;
功能: initialize thread attributes object
使用格式:
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
attr:需要初始化的属性变量
返回值:
成功:0
失败:非0错误码
功能:set detach state attribute in thread attributes object
使用格式:
#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
attr:已初始化的属性变量的地址
detachstate:PTHREAD_CREATE_DETACHED -> 分离属性
PTHREAD_CREATE_JOINABLE -> 非分离属性
返回值:
成功:0
失败:非0错误码
pthread_create(&tid,&attr,...);
功能:destroy thread attributes object
使用格式:
#include <pthread.h>
int pthread_attr_destroy(pthread_attr_t *attr);
attr: 已初始化的属性变量
返回值:
成功:0
失败:非0错误码
#include "head.h"
void *routine(void *arg)
{
int i;
for(i=0;i<10;i++)
{
printf("child %d\n",i);
sleep(1);
}
}
int main()
{
//1. 设置分离属性
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
//2. 创建线程
pthread_t tid;
pthread_create(&tid,&attr,routine,NULL);
//3. 主线程
int i;
for(i=0;i<5;i++)
{
printf("parent %d\n",i);
sleep(1);
}
return 0;
}
功能: detach a thread
使用格式:
#include <pthread.h>
int pthread_detach(pthread_t thread);
thread:需要分离的线程的ID号
返回值:
成功:0
失败:非0错误码
功能:obtain ID of the calling thread
使用格式:
#include <pthread.h>
pthread_t pthread_self(void);
参数:无
返回值: 线程的TID号
例子:
void *routine(void *arg)
{
pthread_detach(pthread_self()); -> 线程就会变成分离属性。
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,routine,NULL);
pause();
}
函数: pthread_cancel() -> man 3 pthread_cancel
功能: send a cancellation request to a thread -> 发送取消请求给线程。
使用格式:
#include <pthread.h>
int pthread_cancel(pthread_t thread);
thread:需要取消的线程的TID号。
返回值:
成功:0
失败:错误码
注意:
收到取消请求就等价于是提前调用pthread_exit(),如果因为取消而退出,则不能把退出状态返回给主线程,但是线程主动退出pthread_exit()可以返回。
#include "head.h"
void *routine(void *arg)
{
int i;
for(i=10;i>0;i--)
{
printf("%d\n",i);
sleep(1);
}
pthread_exit(NULL);
}
int main(int argc,char *argv[])
{
pthread_t tid;
pthread_create(&tid,NULL,routine,NULL); -> 普通线程默认是可以响应的!
sleep(5);
pthread_cancel(tid);
pthread_join(tid,NULL);
return 0;
}
功能: set cancelability state
使用格式:
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
state:
PTHREAD_CANCEL_ENABLE -> 可以响应
PTHREAD_CANCEL_DISABLE -> 不可以响应
oldstate:原来的取消状态的值,不关心原来的状态,则填NULL。
If a cancellation request is received, it is blocked until cancelability is enabled.
假设当前是不能响应取消请求的状态,但是这时收到一个取消请求,那么这个请求会一直阻塞等待,直到线程能响应取消请求为止才会被执行。
#include "head.h"
void *routine(void *arg)
{
int i;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
for(i=0;i<5;i++)
{
sleep(1);
printf("disable %d\n",i);
}
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
for(i=0;i<5;i++)
{
sleep(1);
printf("enable %d\n",i);
}
pthread_exit(NULL);
}
int main(int argc,char *argv[])
{
pthread_t tid;
pthread_create(&tid,NULL,routine,NULL);
sleep(2);
pthread_cancel(tid);
printf("I send cancel to thread!\n");
pthread_join(tid,NULL);
return 0;
}
功能:set cancelability type
使用格式:
#include <pthread.h>
int pthread_setcanceltype(int type, int *oldtype);
type:
PTHREAD_CANCEL_DEFERRED -> 延迟取消
PTHREAD_CANCEL_ASYNCHRONOUS -> 立即取消 -> 默认创建的线程都是立即取消。
oldtype:
原来的取消类型的值,不关心原来的状态,则填NULL。
取消点函数有哪些? -> man 7 pthreads
Cancellation Points
fgetc()
fgets()
fopen()
fprintf()
fputc()
例子:
#include "head.h"
void *routine(void *arg)
{
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
//for循环不属于取消点函数
long i,j;
for(i=0;i<100000;i++)
{
for(j=0;j<100000;j++)
{
}
}
while(1)
{
fputc(‘a‘,stderr); //执行完这次取消点函数之后,再响应取消。
printf("helloworld!\n");
}
pthread_exit(NULL);
}
int main(int argc,char *argv[])
{
pthread_t tid;
pthread_create(&tid,NULL,routine,NULL);
pthread_cancel(tid);
printf("I send cancel to thread!\n");
pthread_join(tid,NULL);
return 0;
}
当线程收到取消请求时,先不要马上响应取消请求,而是要执行一个线程的例程函数,执行完这个函数之后再响应取消。
一般而言,线程例程函数里面写一些释放公共资源的内容,例如:互斥锁,条件变量..
为了防止线程带着一些系统公共资源一起被取消掉,如果带着资源而退出,则其他的线程就无法再次使用该资源。
功能: push thread cancellation clean-up handlers
使用格式:
#include <pthread.h>
void pthread_cleanup_push(void (*routine)(void *),void *arg);
routine:线程取消例程函数 -> 以后收到取消请求,就会先执行该函数!
arg:传递给线程取消例程函数的参数
返回值:无
回顾学习过的例程函数:
信号处理函数: void fun(int sig)
线程例程函数: void *fun(void *arg)
线程取消例程函数: void fun(void *arg)
功能: pop thread cancellation clean-up handlers
使用格式:
#include <pthread.h>
void pthread_cleanup_pop(int execute);
execute: 0 -> 在删除时,不执行该函数,直接删除。
非0 -> 在删除时,先执行一次该函数,再删除。
返回值:无
例子:
pthread_cleanup_push(fun);
...
.. <- 取消请求 执行fun
. <- pthread_exit() 执行fun
... <- return 不执行fun
pthread_cleanup_pop(非0); -> 执行fun
#include "head.h"
void myfun(void *arg)
{
printf("I recv cancel!\n");
}
void *routine(void *arg)
{
pthread_cleanup_push(myfun,NULL); //只要将来我收到取消的请求,就会先执行myfun。
/* 线程持续10秒,在此期间,必定会收到取消请求。 */
int i;
for(i=0;i<10;i++) //在10秒收到取消请求,会执行fun()
{
printf("thread i = %d\n",i);
sleep(1);
}
//pthread_exit(NULL); // -> 还没有来得及删除例程就因为pthread_exit而退出,则执行例程函数。
//return; -> 还没有来得及删除例程就因为return而退出,则不会执行例程函数
//sleep(3);
printf("helloworld!\n");
pthread_cleanup_pop(1); //非0 -> 会执行
//0 -> 不会执行
}
int main(int argc,char *argv[])
{
pthread_t tid;
pthread_create(&tid,NULL,routine,NULL);
//sleep(3);
//pthread_cancel(tid);
//printf("I send cancel to thread!\n");
pthread_join(tid,NULL);
return 0;
}
同步互斥就是使得线程处理任务时有先后顺序,为了解决线程抢占资源问题。
信号量 -> 进程
有名信号量 -> 进程
无名信号量 -> 线程
功能: initialize and open a named semaphore
使用格式:
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
name:有名信号量的名字,要求必须以"/"开头,例如: /sem_test
oflag:O_CREAT -> 不存在则创建
O_EXCL -> 存在则报错
mode:有名信号量的八进制权限,例如: 0777
value:有名信号量的起始值
返回值:
成功:有名信号量的地址
失败:SEM_FAILED -1
P操作: sem_wait() 资源数-1操作 -> man 3 sem_wait
使用格式:
#include <semaphore.h>
int sem_wait(sem_t *sem);
sem:有名信号量的地址
返回值:
成功:0
失败:-1
V操作: sem_post() 资源数+1操作 -> man 3 sem_post
使用格式:
#include <semaphore.h>
int sem_post(sem_t *sem);
sem:有名信号量的地址
返回值:
成功:0
失败:-1
功能:close a named semaphore
使用格式:
#include <semaphore.h>
int sem_close(sem_t *sem);
sem:有名信号量的地址
返回值:
成功:0
失败:-1
功能:remove a named semaphore
使用格式:
#include <semaphore.h>
int sem_unlink(const char *name);
name:有名信号量的名字
返回值:
成功:0
失败:-1
Jack进程:
#include "head.h"
int main()
{
//1. 申请key值
key_t key = ftok(".",10);
//2. 根据key值申请共享内存ID号
int shmid = shmget(key,2048,IPC_CREAT|0666);
//3. 根据ID号申请共享内存的起始地址
char *p = (char *)shmat(shmid,NULL,0);
//4. 往共享内存中写入数据
bzero(p,2048);
//5. 创建并打开一个有名信号量
sem_t *sem = NULL;
sem = sem_open("/sem_test",O_CREAT,0777,0); //说明当前有名信号量的资源数为0
while(1)
{
//想开车进去
fgets(p,2048,stdin);
//资源数+1
sem_post(sem);
if(strncmp(p,"quit",4) == 0)
{
break;
}
}
return 0;
}
Rose进程:
#include "head.h"
int main()
{
//1. 申请key值
key_t key = ftok(".",10);
//2. 根据key值申请共享内存ID号
int shmid = shmget(key,2048,IPC_CREAT|0666);
//3. 根据ID号申请共享内存的起始地址
char *p = (char *)shmat(shmid,NULL,0);
//4. 创建并打开一个有名信号量
sem_t *sem = NULL;
sem = sem_open("/sem_test",O_CREAT,0777,0); //说明当前有名信号量的资源数为0
//5. 不断读取共享内存的数据
while(1)
{
//当前资源数能-1不?
//能 -> 返回 不能 -> 阻塞
sem_wait(sem);
//想开车走
printf("from shm:%s",p);
if(strncmp(p,"quit",4) == 0)
{
break;
}
}
sem_close(sem);
sem_unlink("/sem_test");
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
功能: initialize an unnamed semaphore -> 初始化未命名的信号量
使用格式:
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
sem: 无名信号量的地址
pshared: 0 -> 作用于线程之间 -> 一般都是这个!
非0 -> 作用于进程之间
value:无名信号量的起始值
返回值:
成功:0
失败:-1
P操作: sem_wait() 资源数-1操作 -> man 3 sem_wait
使用格式:
#include <semaphore.h>
int sem_wait(sem_t *sem);
sem:无名信号量的地址
返回值:
成功:0
失败:-1
V操作: sem_post() 资源数+1操作 -> man 3 sem_post
使用格式:
#include <semaphore.h>
int sem_post(sem_t *sem);
sem:无名信号量的地址
返回值:
成功:0
失败:-1
功能:destroy an unnamed semaphore
使用格式:
#include <semaphore.h>
int sem_destroy(sem_t *sem);
sem:无名信号量的地址
返回值:
成功:0
失败:-1
任务:将“helloworld”字符串每隔1S就打印一个字符 -> 完成任务:10秒
要求5个子线程依次打印helloworld,不要同时打印。
正确: helloworldhelloworldhelloworldhelloworldhelloworld
错误: hhhhheeeeellllllllllooooowwwwwooooorrrrrlllllddddd
作业1: 练习4。
作业2: 昨晚的第三题。
作业3: 整理所有学习过的函数。
标签:mod hhhh 操作 err 共享内存 exit 申请 stderr putc
原文地址:https://www.cnblogs.com/zjlbk/p/11353875.html