Manual Pages


ck_cohort(3)             BSD Library Functions Manual             ck_cohort(3)

NAME
     ck_cohort -- generalized interface for lock cohorts

LIBRARY
     Concurrency Kit (libck, -lck)

SYNOPSIS
     #include <ck_cohort.h>

     CK_COHORT_PROTOTYPE(COHORT_NAME cohort_name, LOCK_FXN global_lock_method,
         LOCK_FXN global_unlock_method, LOCK_FXN local_lock_method,
         LOCK_FXN local_unlock_method);

     CK_COHORT_TRYLOCK_PROTOTYPE(COHORT_NAME cohort_name,
         LOCK_FXN global_lock_method, LOCK_FXN global_unlock_method,
         BOOL_LOCK_FXN global_locked_method,
         BOOL_LOCK_FXN global_trylock_method, LOCK_FXN local_lock_method,
         LOCK_FXN local_unlock_method, BOOL_LOCK_FXN local_locked_method,
         BOOL_LOCK_FXN local_trylock_method);

     CK_COHORT_INSTANCE(COHORT_NAME cohort_name);

     CK_COHORT_INIT(COHORT_NAME cohort_name, ck_cohort *cohort,
         void *global_lock, void *local_lock, unsigned int pass_limit);

     CK_COHORT_LOCK(COHORT_NAME cohort_name, ck_cohort *cohort,
         void *global_context, void *local_context);

     CK_COHORT_UNLOCK(COHORT_NAME cohort_name, ck_cohort *cohort,
         void *global_context, void *local_context);

     Where LOCK_FXN refers to a method with the signature
     void(void *lock, void *context)
     BOOL_LOCK_FXN refers to a method with the signature
     bool(void *lock, void *context)

     The context
     argument in each signature is used to pass along any additional informa-
     tion that the lock might need for its lock, unlock and trylock methods.
     The values for this argument are provided to each call to
     CK_COHORT_LOCK(3), CK_COHORT_UNLOCK(3), CK_COHORT_LOCKED(3), and
     CK_COHORT_TRYLOCK(3)

DESCRIPTION
     ck_cohort.h provides an interface for defining lock cohorts with arbi-
     trary lock types.  Cohorts are a mechanism for coordinating threads on
     NUMA architectures in order to reduce the frequency with which a lock is
     passed between threads on different clusters.

     Before using a cohort, the user must define a cohort type using either
     the CK_COHORT_PROTOTYPE() or the CK_COHORT_TRYLOCK_PROTOTYPE() macros.
     These macros allow the user to specify the lock methods that they would
     like the cohort to use.  See the CK_COHORT_PROTOTYPE(3) and
     CK_COHORT_TRYLOCK_PROTOTYPE(3) man pages for more details.

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

           #include <ck_pr.h>
           #include <ck_cohort.h>
           #include <ck_spinlock.h>

           /*
            * Create cohort methods with signatures that match
            * the required signature
            */
           static void
           ck_spinlock_lock_with_context(ck_spinlock_t *lock, void *context)
           {
                   (void)context;
                   ck_spinlock_lock(lock);
                   return;
           }

           static void
           ck_spinlock_unlock_with_context(ck_spinlock_t *lock, void *context)
           {
                   (void)context;
                   ck_spinlock_unlock(lock);
                   return;
           }

           static bool
           ck_spinlock_locked_with_context(ck_spinlock_t *lock, void *context)
           {
                   (void)context;
                   return ck_spinlock_locked(lock);
           }

           /*
            * define a cohort type named "test_cohort" that will use
            * the above methods for both its global and local locks
            */
           CK_COHORT_PROTOTYPE(test_cohort,
                   ck_spinlock_lock_with_context, ck_spinlock_unlock_with_context, ck_spinlock_locked_with_context,
                   ck_spinlock_lock_with_context, ck_spinlock_unlock_with_context, ck_spinlock_locked_with_context)

           static ck_spinlock_t global_lock = CK_SPINLOCK_INITIALIZER;
           static unsigned int ready;

           static void *
           function(void *context)
           {
                   CK_COHORT_INSTANCE(test_cohort) *cohort = context;

                   while (ready == 0);

                   while (ready > 0) {
                           /*
                            * acquire the cohort lock before performing critical section.
                            * note that we pass NULL for both the global and local context
                            * arguments because neither the lock nor unlock functions
                            * will use them.
                            */
                           CK_COHORT_LOCK(test_cohort, cohort, NULL, NULL);

                           /* perform critical section */

                           /* relinquish cohort lock */
                           CK_COHORT_UNLOCK(test_cohort, cohort, NULL, NULL);
                   }

                   return NULL;
           }

           int
           main(void)
           {
                   unsigned int nthr = 4;
                   unsigned int n_cohorts = 2;
                   unsigned int i;

                   /* allocate 2 cohorts of the defined type */
                   CK_COHORT_INSTANCE(test_cohort) *cohorts =
                       calloc(n_cohorts, sizeof(CK_COHORT_INSTANCE(test_cohort)));

                   /* create local locks to use with each cohort */
                   ck_spinlock_t *local_locks =
                           calloc(n_cohorts, sizeof(ck_spinlock_t));

                   pthread_t *threads =
                           calloc(nthr, sizeof(pthread_t));

                   /* initialize each of the cohorts before using them */
                   for (i = 0 ; i < n_cohorts ; ++i) {
                           CK_COHORT_INIT(test_cohort, cohorts + i, &global_lock, local_locks + i,
                                   CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT);
                   }

                   /* start each thread and assign cohorts equally */
                   for (i = 0 ; i < nthr ; ++i) {
                           pthread_create(threads + i, NULL, function, cohorts + (i % n_cohorts));
                   }

                   ck_pr_store_uint(&ready, 1);
                   sleep(10);
                   ck_pr_store_uint(&ready, 0);

                   for (i = 0 ; i < nthr ; ++i) {
                           pthread_join(threads[i], NULL);
                   }

                   return 0;
           }

SEE ALSO
     CK_COHORT_PROTOTYPE(3), CK_COHORT_TRYLOCK_PROTOTYPE(3),
     CK_COHORT_INSTANCE(3), CK_COHORT_INITIALIZER(3), CK_COHORT_INIT(3),
     CK_COHORT_LOCK(3), CK_COHORT_UNLOCK(3), CK_COHORT_LOCKED(3),
     CK_COHORT_TRYLOCK(3),

     Additional information available at http://concurrencykit.org/

                              February 24, 2013.