APUE学习笔记-11.6线程同步

(1)不存在一致性问题的情况

    1)每个线程使用的变量都是其他线程不会使用和修改的。

    2)变量是只读的。

    3)对变量的修改操作时原子操作,则不存在竞争。

    4)数据总是顺序一致出现的。(有计算机体系结构决定)

<322>使用互斥量保护数据结构

#include <stdlib.h>
#include <pthread.h>

struct foo {
	int             f_count;
	pthread_mutex_t f_lock;
	int             f_id;
	/* ... more stuff here ... */
};

struct foo *
foo_alloc(int id) /* allocate the object */
{
	struct foo *fp;

	if ((fp = malloc(sizeof(struct foo))) != NULL) {
		fp->f_count = 1;
		fp->f_id = id;
		if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {
			free(fp);
			return(NULL);
		}
		/* ... continue initialization ... */
	}
	return(fp);
}

void
foo_hold(struct foo *fp) /* add a reference to the object */
{
	pthread_mutex_lock(&fp->f_lock);
	fp->f_count++;
	pthread_mutex_unlock(&fp->f_lock);
}

void
foo_rele(struct foo *fp) /* release a reference to the object */
{
	pthread_mutex_lock(&fp->f_lock);
	if (--fp->f_count == 0) { /* last reference */
		pthread_mutex_unlock(&fp->f_lock);
		pthread_mutex_destroy(&fp->f_lock);
		free(fp);
	} else {
		pthread_mutex_unlock(&fp->f_lock);
	}
}

(1)

int  pthread_mutex_init(pthread_mutex_t  *mutex,  const  pthread_mutexattr_t *mutexattr);

mutexattr:NULL表示用默认的属性初始化互斥量。


int pthread_mutex_lock(pthread_mutex_t *mutex);

对互斥量进行加锁,若互斥量已经上锁,则调用线程将阻塞直到互斥量被解锁。


int pthread_mutex_trylock(pthread_mutex_t *mutex);

尝试对互斥量进行加锁,有2种结果:

    锁住互斥量,直接返回0。

    失败,返回EBUSY。


int pthread_mutex_unlock(pthread_mutex_t *mutex);

对互斥量解锁。


int pthread_mutex_destroy(pthread_mutex_t *mutex);

动态分配的互斥量,(通过调用malloc函数)在释放内存前需调用此函数。

<337>在一个任务上合作的多个线程之间如何用屏障进行同步

这个例子中,使用8个线程分解了800万个数的排序工作。每个线程用堆排序算法对100万个数进行排序。最后主线程调用一个函数对这些结果进行合并。

#include "apue.h"
#include <pthread.h>
#include <limits.h>
#include <sys/time.h>

#define NTHR   8				/* number of threads */
#define NUMNUM 8000000L			/* number of numbers to sort */
#define TNUM   (NUMNUM/NTHR)	/* number to sort per thread */

long nums[NUMNUM];
long snums[NUMNUM];

pthread_barrier_t b;

#ifdef SOLARIS
#define heapsort qsort
#else
extern int heapsort(void *, size_t, size_t,
                    int (*)(const void *, const void *));
#endif

/*
 * Compare two long integers (helper function for heapsort)
 */
int
complong(const void *arg1, const void *arg2)
{
	long l1 = *(long *)arg1;
	long l2 = *(long *)arg2;

	if (l1 == l2)
		return 0;
	else if (l1 < l2)
		return -1;
	else
		return 1;
}

/*
 * Worker thread to sort a portion of the set of numbers.
 */
void *
thr_fn(void *arg)
{
	long	idx = (long)arg;

	heapsort(&nums[idx], TNUM, sizeof(long), complong);
	pthread_barrier_wait(&b);

	/*
	 * Go off and perform more work ...
	 */
	return((void *)0);
}

/*
 * Merge the results of the individual sorted ranges.
 */
void
merge()
{
	long	idx[NTHR];
	long	i, minidx, sidx, num;

	for (i = 0; i < NTHR; i++)
		idx[i] = i * TNUM;
	for (sidx = 0; sidx < NUMNUM; sidx++) {
		num = LONG_MAX;
		for (i = 0; i < NTHR; i++) {
			if ((idx[i] < (i+1)*TNUM) && (nums[idx[i]] < num)) {
				num = nums[idx[i]];
				minidx = i;
			}
		}
		snums[sidx] = nums[idx[minidx]];
		idx[minidx]++;
	}
}

int
main()
{
	unsigned long	i;
	struct timeval	start, end;
	long long		startusec, endusec;
	double			elapsed;
	int				err;
	pthread_t		tid;

	/*
	 * Create the initial set of numbers to sort.
	 */
	srandom(1);
	for (i = 0; i < NUMNUM; i++)
		nums[i] = random();

	/*
	 * Create 8 threads to sort the numbers.
	 */
	gettimeofday(&start, NULL);
	pthread_barrier_init(&b, NULL, NTHR+1);
	for (i = 0; i < NTHR; i++) {
		err = pthread_create(&tid, NULL, thr_fn, (void *)(i * TNUM));
		if (err != 0)
			err_exit(err, "can't create thread");
	}
	pthread_barrier_wait(&b);
	merge();
	gettimeofday(&end, NULL);

	/*
	 * Print the sorted list.
	 */
	startusec = start.tv_sec * 1000000 + start.tv_usec;
	endusec = end.tv_sec * 1000000 + end.tv_usec;
	elapsed = (double)(endusec - startusec) / 1000000.0;
	printf("sort took %.4f seconds\n", elapsed);
	for (i = 0; i < NUMNUM; i++)
		printf("%ld\n", snums[i]);
	exit(0);
}

(1)

屏障用于协调多个线程并行工作。

它们允许任意数量的线程等待,直到所有的线程完成处理工作,而不需要退出。所有线程到达屏障后可以接着工作。

(2)

srandom函数:设定随机数种子。

random函数:产生随机数。

(3)

int pthread_barrier_init(pthread_barrier_t *restrict barrier

              const pthread_barrierattr_t *restrict attr, unsigned count);

初始化屏障。
count参数:在允许所有线程继续运行之前,必须到达屏障的线程数目。

attr参数:指定屏障对象的属性。NULL表示用默认属性初始化屏障。


int pthread_barrier_wait(pthread_barrier_t *barrier);

调用此函数的线程在屏障未满足条件时,会进入休眠状态。若该线程是最后一个调用此函数的线程,满足屏障计数,则所有的线程都被唤醒。

你可能感兴趣的:(APUE学习笔记-11.6线程同步)