linux thread 同步 操作 实例

1:linux thread介绍

如果需要只终止某个线程而不终止整个进程,可以有三种方法:
从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。
一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
线程可以调用pthread_exit终止自己。
#include <pthread.h>

void pthread_exit(void *value_ptr);
value_ptr是void *类型,和线程函数返回值的用法一样,其它线程可以调用pthread_join获得这个指针。
需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,
不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
#include <pthread.h>
int pthread_join(pthread_t thread, void **value_ptr);
返回值:成功返回0,失败返回错误号
调用该函数的线程将挂起等待,直到id为thread的线程终止。
thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,

总结如下:如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。如果thread线程被别的线程调用pthread_cancel异常终止掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED。

如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。

下面的实例主要是对简单的API进行说明:

void *thr_fn1(void *arg)
{
		printf("thread 1 returning\n");
		return (void *)100;
}
void *thr_fn2(void *arg)
{
		printf("thread 2 exiting\n");
		pthread_exit((void *)200);
}
void *thr_fn3(void *arg)
{
		while(1)
		{
			printf("thread 3 writing\n");
			sleep(1);
		}
}

void threadexitstatus()
{
		pthread_t tid; void *tret;
		pthread_create(&tid, NULL, thr_fn1, NULL);
		pthread_join(tid, &tret);
		printf("thread 1 exit code %d\n", (int)tret);
		pthread_create(&tid, NULL, thr_fn2, NULL);
		pthread_join(tid, &tret);
		printf("thread 2 exit code %d\n", (int)tret);
		pthread_create(&tid, NULL, thr_fn3, NULL);
		sleep(3);
		pthread_cancel(tid);
		pthread_join(tid, &tret);
		printf("thread 3 exit code %d\n", (int)tret);
		return 0;
/*

[root@localhost /wlan/plc/workspace/signatest/Debug]$./signatest 3
thr_fn1 pid 13323 tid 3078593392 (0xb77f9b70)
thread 1 returning
thread 1 exit code 100
thr_fn2 pid 13323 tid 3078593392 (0xb77f9b70)
thread 2 exiting
thread 2 exit code 200
thr_fn3 pid 13323 tid 3078593392 (0xb77f9b70)
thread 3 writing
thread 3 writing
thread 3 writing
thread 3 exit code -1
[root@localhost /wlan/plc/workspace/signatest/Debug]$

 */
}


2:linux:同步之 (Condition Variable)条件变量

线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,
而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行。
在pthread库中通过条件变量(Condition Variable)来阻塞等待一个条件,或者唤醒等待这个条件的线程。
Condition Variable用pthread_cond_t类型的变量表示,可以这样初始化和销毁:


#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
返回值:成功返回0,失败返回错误号。和Mutex的初始化和销毁类似,pthread_cond_init函数初始化一个Condition Variable,attr参数为NULL则表示缺省属性,pthread_cond_destroy函数销毁一个Condition Variable。如果ConditionVariable是静态分配的,也可以用宏定义PTHEAD_COND_INITIALIZER初始化,相当于用pthread_cond_init函数初始化并且attr参数为NULL。
#include <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
返回值:成功返回0,失败返回错误号。
可见,一个Condition Variable总是和一个Mutex搭配使用的。pthread_cond_timedwait函数还有一个额外的参数可以设定等待超时,如果到达了abstime所指定的时刻仍然没有别的线程来唤醒当前线程,就返回ETIMEDOUT。
一个线程可以调用pthread_cond_signal唤醒在某个Condition Variable上等待的另一个线程,也可以调用pthread_cond_broadcast唤醒在这个Condition Variable上等待的所有线程。

//分别对条件变量和互斥量进行初始化。

static pthread_mutex_t pthreadmtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

static int avail = 0;
static int productNum = 0;
static void * threadFunc(void *arg)
{
    int cnt = atoi((char *) arg);
    int s, j;
    printf("need Num:%d \n",cnt);
    while(1)
    {
      usleep(2);
//    	sleep(2);
 //   	sleep(1);
        /* Code to produce a unit omitted */

        s = pthread_mutex_lock(&pthreadmtx);
        if (s != 0)
            errExitEN(s, "pthread_mutex_lock");

        avail++;        /* Let consumer know another unit is available */
        productNum++;
        printf("Num Product:%d\n",productNum);
        s = pthread_mutex_unlock(&pthreadmtx);
        if (s != 0)
            errExitEN(s, "pthread_mutex_unlock");

        s = pthread_cond_signal(&cond);         /* Wake sleeping consumer */
        if (s != 0)
            errExitEN(s, "pthread_cond_signal");
    }

    return NULL;
}
void threadConditionMutex(int argc, char *argv[])
{
    pthread_t tid;
    int s, j;
    int totRequired;            /* Total number of units that all threadswill produce */
    int numConsumed;            /* Total units so far consumed */
    Boolean done;
    time_t t;
    struct timespec request;
    struct timeval start;
    t = time(NULL);

    /* Create all threads */

    totRequired = 0;
    {
        totRequired += atoi(argv[1]);
        s = pthread_create(&tid, NULL, threadFunc, argv[1]);
        if (s != 0)
            errExitEN(s, "pthread_create");
    }

    /* Use a polling loop to check for available units */

    numConsumed = 0;
    done = FALSE;

    for (;;)
    {
        s = pthread_mutex_lock(&pthreadmtx);
        if (s != 0)
            errExitEN(s, "pthread_mutex_lock");
        if (gettimeofday(&start, NULL) == -1)
            errExit("gettimeofday");
        request.tv_sec = start.tv_sec+1;
        request.tv_nsec = start.tv_usec*1000;

     //   s = pthread_cond_wait(&cond, &pthreadmtx);
        s = pthread_cond_timedwait(&cond, &pthreadmtx,&request);
        if (s == 0)
        {
        	/* Consume all ava *ilable units*/
            numConsumed ++;
            avail--;
            printf("T=%ld: numConsumed=%d avail:%d\n", (long) (time(NULL) - t),numConsumed,avail);

            done = numConsumed >= totRequired;
        }
        else
        {
        	printf("pthread_cond_timedwait timeout...............\n");
        }

        s = pthread_mutex_unlock(&pthreadmtx);
        if (s != 0)
            errExitEN(s, "pthread_mutex_unlock");

        if (done)
            break;
        usleep(200);
    }

    exit(EXIT_SUCCESS);
}


3:linux Semaphore 信号量

信号量(Semaphore)和Mutex类似,表示可用资源的数量,和Mutex不同的是这个数量可以大于1。
POSIX semaphore信号量不仅可用于同一进程的线程间同步,也可用于不同进程间的同步。
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_post(sem_t * sem);
int sem_destroy(sem_t * sem);
semaphore变量的类型为sem_t,sem_init()初始化一个semaphore变量,value参数表示可用资源的数量,
pshared参数为0表示信号量用于同一进程的线程间同步,
在用完semaphore变量之后应该调用sem_destroy()释放与semaphore相关的资源。
调用sem_wait()可以获得资源,使semaphore的值减1,如果调用sem_wait()时semaphore的值已经是0,
则挂起等待。如果不希望挂起等待,可以调用sem_trywait()。
调用sem_post()可以释放资源,使semaphore的值加1,同时唤醒挂起等待的线程。

示例代码如下:

#include <semaphore.h>
#define NUM 5
int queue[NUM];
sem_t blank_number, product_number;
int product_num =0;
int consum_num =0;
void *producer(void *arg)
{ int p = 0;
	while (1)
	{
		sem_wait(&blank_number);
		queue[p] = p;
		printf("Produce %d\n", queue[p]);
		product_num++;
		sem_post(&product_number);
		p = (p+1)%NUM;
		sleep(1);
	}
}
void *consumer(void *arg)
{
	int c = 0;
	while (1)
	{
		sem_wait(&product_number);
		printf("Consume %d\n", queue[c]);
		queue[c] = 0;
		consum_num++;
		sem_post(&blank_number);
		c = (c+1)%NUM;
		sleep(1);
	}
}
void semtest()
{
	pthread_t pid, cid;
	sem_init(&blank_number, 0, NUM);
	sem_init(&product_number, 0, 2);
	pthread_create(&pid, NULL, producer, NULL);
	sleep(4);
	pthread_create(&cid, NULL, consumer, NULL);
	while(1)
	{
		printf("product_num:%d \t consum_num:%d avail:%d\n",product_num,consum_num,(product_num-consum_num));
		sleep(1);
	}
	pthread_join(pid, NULL);
	pthread_join(cid, NULL);
	sem_destroy(&blank_number);
	sem_destroy(&product_number);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

家有工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值