【C】线程控制

创建线程
#include <pthread.h>
 
int pthread_create(pthread_t * thread,
    const pthread_attr_t * attr,
    void *(*start_routine)(void*), void * arg);

返回值:成功返回0,失败返回错误号。

thread:成功返回后,新创建的线程的id被填写到 thread参数所指向的内存单元。线程id的类型是pthread_t,它只在当前进程中保证是唯一的,在不同的系统中pthread_t这个类型有不同的实现,它可能是一个整数值,也可能是一个结构体,也可能是一个地址,所以不能简单地当成整数用printf打印,调用pthread_self()可以获取当前线程地id。

attr:表示线程属性,这里暂不讨论。

start_routine和arg:新线程所指向的代码由函数指针start_routine决定。start_routine函数接收一个参数arg,该参数的类型为void *,这个指针按什么类型解释由调用者自己定义,start_routine的返回值类型也是void *,这个指针的函数的含义同样由调用者自己定义。

#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>

static void thread_func(const char *arg)
{
	printf("arg=%s\n", arg);
	pthread_t tid = pthread_self();
	printf("new thread pid=%u\n", (uint32_t)tid);
}

int main(void)
{
	pthread_t id;
	int ret = pthread_create(&id, NULL, thread_func, "i am iron man");
	if (0 != ret)
	{
		printf("pthread_carete error=%s", strerror(ret));
	}
	printf("new thread pid=%u\n", (uint32_t)id);

	while (1)
	{
		usleep(1000);
	}

	return 0;
}

输出结果为:

new thread pid=1
arg=i am iron man
new thread pid=1

可知,在window上,thread_t类型是一个整型值。

终止线程

如果需要终止某个线程而不终止整个进程,可以有三种方法:

  • 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit
  • 一个线程可以调用pthread_cancel终止同一进程中地另一个线程。
  • 线程可以调用pthread_exit终止自己。

在介绍终止之前,我们先介绍一下pthread_join函数。

#include <pthread.h>
 
int pthread_join(pthread_t thread, void **value_ptr);//返回值:成功返回0,失败返回错误号。

调用该函数地线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态时不同的,总结如下:

  • 如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。
  • 如果thread线程被别的线程调用thread_cancel异常终止掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED
  • 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元里存放的是传给pthread_exit的参数。

如果对thread线程的终止状态不感兴趣,可以传NULLvalue_ptr参数。

一般情况下,线程终止后,其终止状态一直保留到其他线程调用pthread_join获取它的状态为止。但是线程也可以被设置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL。对一个尚未detach的线程调用pthread_joinpthread_detach都可以把该线程设置为detach状态,也就是说,不能对同一线程调用两次pthread_join,或者如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。

#include <pthread.h>
 
int pthread_detach(pthread_t tid);//返回值:成功返回0,失败返回错误号。
#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>

static void *thread1_func(const char *arg)
{
	printf("arg=%s\n", arg);
	pthread_t tid = pthread_self();
	printf("new thread pid=%u\n", (uint32_t)tid);
	return (void *)0xFF;
}

static void *thread2_func(const char *arg)
{
	printf("arg=%s\n", arg);
	pthread_t tid = pthread_self();
	printf("new thread pid=%u\n", (uint32_t)tid);
	pthread_exit((void *)0xFE);
}

static void *thread3_func(const char *arg)
{
	printf("arg=%s\n", arg);
	pthread_t tid = pthread_self();
	printf("new thread pid=%u\n", (uint32_t)tid);
	while (1)
	{
		printf("%s running\n", arg);
        usleep(5000 * 100);
	}
}

int main(void)
{
	pthread_t id1;
	int ret1 = pthread_create(&id1, NULL, thread1_func, "i am thread1");
	if (0 != ret1)
	{
		printf("pthread_carete error=%s", strerror(ret1));
	}
	void *thread1_ret;
	pthread_join(id1, &thread1_ret);
	printf("thread1_ret=%d\n", (int)thread1_ret);

	pthread_t id2;
	int ret2 = pthread_create(&id2, NULL, thread2_func, "i am thread2");
	if (0 != ret2)
	{
		printf("pthread_carete error=%s", strerror(ret2));
	}
	void *thread2_ret;
	pthread_join(id2, &thread2_ret);
	printf("thread2_ret=%d\n", (int)thread2_ret);

	pthread_t id3;
	int ret3 = pthread_create(&id3, NULL, thread3_func, "i am thread3");
	if (0 != ret3)
	{
		printf("pthread_carete error=%s", strerror(ret3));
	}
	void *thread3_ret;
	sleep(1);
	pthread_cancel(id3);
	pthread_join(id3, &thread3_ret);
	printf("thread3_ret=%d\n", (int)thread3_ret);

	while (1)
	{
		usleep(1000);
	}

	return 0;
}

输出为:

arg=i am thread1
new thread pid=1
thread1_ret=255
arg=i am thread2
new thread pid=3
thread2_ret=254
arg=i am thread3
new thread pid=4
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running
i am thread3 running

我们可以看到,线程1和线程2的终止与我们的预期一样,但是线程3使用pthread_cancel()似乎没有真正终止线程。那这里就需要引用另外两个概念了。

线程终止状态
	@state:
	PTHREAD_CANCEL_ENABLE:
		线程对cancel信号立即有反应,将设置为CANCEL状态 (默认)
	PTHREAD_CANCEL_DISABLE:
		如果线程state为不可取消,线程不理会信号,继续执行,而使用cancel函数的线程会一直阻塞到可取消状态
	@oldstate:
		NULL:state写入有效,即当前只想设置属性,而不关心原来的属性
	不为NULL:state不写入,保持原有的设定,且获取原来的属性
	
	return:
	成功返回0,错误返回errno	
		EINVAL:无效的state

int pthread_setcancelstate(int state,int *oldstate)
线程终止类型
	@type:
		PTHREAD_CANCEL_DEFERRED:
			运行到下一个取消点就退出 (默认)
		PTHREAD_CANCEL_ASYNCHRONOUS:
			直接退出
	@oldtyoe:
		NULL:type写入有效,即当前只想设置属性,而不关心原来的属性
		不为NULL:type不写入,保持原有的设定,且获取原来的属性
		
	return:
		成功返回0,错误返回errno	
			EINVAL:无效的type
int pthread_setcanceltype(int type,int *oldtype)

所以,如下想要使用pthread_cancel终止线程,那么我们必须在线程函数中调用

pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

当我们把线程函数改成:

static void *thread3_func(const char *arg)
{
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
	printf("arg=%s\n", arg);
	pthread_t tid = pthread_self();
	printf("new thread pid=%u\n", (uint32_t)tid);
	while (1)
	{
		printf("%s running\n", arg);
		usleep(5000 * 100);
	}
}

那么就可以正常终止了,输出结果如下:

arg=i am thread1
new thread pid=1
thread1_ret=255
arg=i am thread2
new thread pid=3
thread2_ret=254
arg=i am thread3
new thread pid=4
i am thread3 running
i am thread3 running
thread3_ret=-559038737
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值