• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Implementing a "Synchronous Channel" with dispatch
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Implementing a "Synchronous Channel" with dispatch


  • Subject: Re: Implementing a "Synchronous Channel" with dispatch
  • From: Andreas Grosam <email@hidden>
  • Date: Wed, 14 Sep 2011 18:38:25 +0200

On Sep 14, 2011, at 4:20 PM, Dave Zarzycki wrote:

> Andreas,
>
> This is probably not the answer you're looking for, but when we find coding patterns like this in the OS, we advice developers to replace this pattern with a GCD queue and use either dispatch_sync() or dispatch_async(). The reason for this advice is because parking threads to wait for events isn't an efficient use of system resources.
>
> davez

Well, I *am* using GCD  ;)

A "Synchronous Channel" (or Synchronous Queue) is a well known pattern used in multithreading. Basically, it is used to "hand off" objects from one thread to another, with the requirement that the "producer" waits until a "consumer" took the object.

The synchronous queue is a blocking queue, and this blocking is used as a means to "throttle" the use of system resources.

In certain scenarios there is no other way to stop some code which allocates resources by blocking its thread. When you use dispatch queues to schedule "work items", these work items may contain resources. But consider, these resources stay allocated as long as the block waits in the dispatch queue to be processed by some other task and deallocates the resources again when it is finished.

So, imagine this:
A producer, and consumer in action:
while (!canceled) {
   NSData * data = … create new data
   dispatch_async(process_data_queue, ^{
	[consumer processData:data];
   });
}

If you do this, you may very probable drive your system into an insane state if the "producer rate" is higher than the "consumer rate". In order to fix the balance, you would use semaphores, and the Synchronous Channel is exactly this.


Regards
Anderas





>
>
>
>
> On Sep 14, 2011, at 5:40 AM, Andreas Grosam wrote:
>
>> Dear List,
>>
>> I've implemented a simple "Synchronous Channel" using dispatch lib.
>> A "synchronous channel" is an actor in which each producer offering an item (via a put operation) must wait for a consumer to take this item (via a get operation), and vice versa.
>>
>> The following is probably the simplest implementation, which lacks some important features like timeout etc.
>>
>> But anyway, is the following a proper and *efficient* implementation when using dispatch lib where consumers and producers will be scheduled in queues and the semaphore is implemented using dispatch_semaphore?
>>
>> Any hints to improve this?
>>
>>
>> template <typename T>
>> class SimpleSynchronousChannel {
>> public:
>>   SimpleSynchronousChannel()
>>   : sync_(0), send_(1), recv_(0)
>>   {
>>   }
>>
>>   void put(const T& v) {
>>       send_.wait();
>>       value_ = v;
>>       recv_.signal();
>>       sync_.wait();
>>   }
>>
>>   T get() {
>>       recv_.wait();
>>       T result = value_;
>>       sync_.signal();
>>       send_.signal();
>>       return result;
>>   }
>>
>> private:
>>   T           value_;
>>   semaphore   sync_;
>>   semaphore   send_;
>>   semaphore   recv_;
>> };
>>
>>
>>
>> benchmark info: if I run concurrently one producer (performing put()) and one consumer (performing get()), I get a throughput of about 200.000 items/sec on a MacBookPro)
>>
>>
>>
>>
>>
>>
>> class semaphore is a simple wrapper around dispatch_semaphore:
>>
>>
>>   class semaphore : noncopyable {
>>   public:
>>       explicit semaphore(long n) : sem_(dispatch_semaphore_create(n)) {
>>           assert(sem_);
>>       }
>>       ~semaphore() {
>>           dispatch_release(sem_);
>>       }
>>       void signal()  {
>>           dispatch_semaphore_signal(sem_);
>>       }
>>       bool wait()  { return dispatch_semaphore_wait(sem_, DISPATCH_TIME_FOREVER) == 0; }
>>       bool wait(double timeout_sec)  {
>>           long result = dispatch_semaphore_wait(sem_,
>>                                                 timeout_sec >= 0 ?
>>                                                 dispatch_time(DISPATCH_TIME_NOW, timeout_sec*1e9)
>>                                                 : DISPATCH_TIME_FOREVER);
>>           return result == 0;
>>       }
>>
>>   private:
>>       dispatch_semaphore_t sem_;
>>   };
>>

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Follow-Ups:
    • Re: Implementing a "Synchronous Channel" with dispatch
      • From: Dave Zarzycki <email@hidden>
    • Re: Implementing a "Synchronous Channel" with dispatch
      • From: Kyle Sluder <email@hidden>
References: 
 >Implementing a "Synchronous Channel" with dispatch (From: Andreas Grosam <email@hidden>)
 >Re: Implementing a "Synchronous Channel" with dispatch (From: Dave Zarzycki <email@hidden>)

  • Prev by Date: Re: How to subscribe to Xcode users list?
  • Next by Date: UISplitViewController + UIView on UIWindow
  • Previous by thread: Re: Implementing a "Synchronous Channel" with dispatch
  • Next by thread: Re: Implementing a "Synchronous Channel" with dispatch
  • Index(es):
    • Date
    • Thread